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