哎,想写一个解题报告的,但是,写出来看着就不舒服,最后还是删了。囧
这个题,明显的是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;
}