似乎是比较基础的一道用到polya定理的题,为了这道题扣了半天组合数学和数论。
等价的题意:可以当成是给正n边形的顶点染色,旋转同构,两种颜色,假设是红蓝,相邻顶点不能同时为蓝。
大概思路:在不考虑旋转同构的情况下,正n边形有fib(n+1)+fib(n-1)种染色方法(n==1特判),然后后面就是套公式了,涉及到要用欧拉定理优化,不然会T。(理论的东西看下组合数学书中polya计数部分,及数论书中欧拉函数部分中 n的约数的欧拉函数,感觉看博客不如系统的看看书,再结合一下网上一些比较基础的polya题来理解。)
题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=5868
#include<bits/stdc++.h> using namespace std; typedef long long LL; const LL mod=1e9+7; LL Eular(LL n) { LL ret=n; for(LL i=2; i*i<= n; i++) { if(n%i==0) { ret-=ret/i; while(n%i==0) n/= i; } } if(n>1) ret-=ret/n; return ret; } LL qpow(LL n,LL k) { LL res=1; for(; k; k>>=1) { if(k&1) res=res*n%mod; n=n*n%mod; } return res; } LL inv(LL x) { return qpow(x,mod-2); } const LL N=2; struct Mat { LL mat[N][N]; }; Mat Mut(Mat a,Mat b) { LL i,j,k; Mat c; memset(c.mat,0,sizeof(c.mat)); for(k=0; k<N; k++) { for(i=0; i<N; i++) { if(a.mat[i][k]) for(j=0; j<N; j++) { if(b.mat[k][j]) c.mat[i][j]=c.mat[i][j]+a.mat[i][k]*b.mat[k][j]; c.mat[i][j]=c.mat[i][j]%mod; } } } return c; } Mat Pow(Mat a,LL n) { Mat c; for(int i = 0; i < N; ++i) for(int j = 0; j < N; ++j) c.mat[i][j] = (i == j); for(; n; n>>=1) { if(n&1) c=Mut(c,a); a=Mut(a,a); } return c; } LL fib(LL x) { if(x==0) return 0; Mat A; A.mat[0][0]=A.mat[0][1]=A.mat[1][0]=1; A.mat[1][1]=0; Mat A_=Pow(A,x-1); return A_.mat[0][0]; } LL polya(LL n) { if(n==1) return 2; LL ans=0,i; for(i=1;i*i<n;i++) if(n%i==0) { ans=(ans+Eular(i)*(fib(n/i-1)+fib(n/i+1)))%mod; ans=(ans+Eular(n/i)*(fib(i-1)+fib(i+1)))%mod; } if(i*i==n) ans+=Eular(i)*(fib(i-1)+fib(i+1))%mod; return ans*inv(n)%mod; } int main() { LL n; while(cin>>n) cout<<polya(n)<<' '; }