哎,想寫一個解題報告的,但是,寫出來看着就不舒服,最後還是刪了。囧
這個題,明顯的是polya問題,最核心的東西是:當這個旋轉a個角度之後和原先的重合,那麼旋轉2*a個角度之後仍然重合,當然,旋轉一週(36000)之後仍然重合。是的,我們可以看到,這個最小的a“區間”就是“項鍊”問題的一個珠子,然後就是若干個珠子的polya,直接模板!!求這個a的時候用到的東西是 :角度之間的距離然後kmp,
ok,不想多寫了,放上代碼吧,雖然貼代碼不是什麼好習慣,我就是給自己看的,上面的東西算是提示,goodluck!
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 360010,P = 100000007,S = 360000;
int s,n;
int data[N],dis[N];
int next[N];
void get_next(){
int i,j=-1;
next[0]=-1;
for(i=1;i<=n;i++){ //dis[j]是不是可以理解爲i的前一個字符的next值所指想的字符
while(j>-1&&dis[j+1]!=dis[i])j=next[j];
if(dis[j+1]==dis[i])j++;
next[i]=j;
}
}
//得到最小,使用dis數組,長度是n,從0開始,ok kmp實現
int getMin()
{
int re = n;
get_next();
int l=(n-1)-next[n-1];
if(n%l==0)re = l;
return re;
}
long long pow(int a,int n)
{
long long ret=1;
long long A=a;
while(n)
{
if (n & 1)
{
ret = (ret*A%P);
}
A = (A*A%P);
n>>=1;
}
return ret;
}
long long GCD(long long a,long long b) {while(b){ long long t=a%b;a=b;b=t;}return a;}
long long inv( long long n )
{
return pow( n, P - 2 )%P;
}
long long polya(long long c,int n)
{
long long ans = 0;
for(int i = 1;i <= n;i++)
ans = (ans+pow(c,GCD(n,i)))%P;
return (ans*inv(n)%P);
}
int main()
{
while(scanf("%d%d",&s,&n) != EOF)
{
if(s == -1 && n == -1) break;
for(int i = 0;i < n;i++)
scanf("%d",&data[i]);
sort(data,data+n);
for(int i = 0;i < n;i++)
dis[i] = (data[(i+1)%n]-data[i]+S)%S;
int t = getMin();
cout << polya(pow(s,t),n/t) << "\n";
}
return 0;
}