poj 1286 polya 定理
题意:用三种颜色的珠子串成长度为N(N<24)的项链,经过旋转和翻转所得的项链视为同一种项链,求共能组成几条不同的项链。
分析:
1、旋转:置换的个数是n个,第i个置换的循环节个数是gcd(n,i)个。
证明:经过 LCM ( i ,n ) / i 次旋转回到自身,循环节的长度是 LCM( i , n ) / i ,n / ( LCM( i , n ) / i )就是循环节的个数,n / ( LCM( i , n ) / i ) = gcd( n , i )
2、翻转:找循环节的关键是找对称轴,n要分奇偶性。
当n = 2 * k + 1,对称轴就是每个点和圆心的连线,共n条,除了这个点没变,其他的点都跟对称的那个点置换了,所以循环节的个数是k+1。
当n = 2 * k,对称轴是每个点和对面的点的连线,共k条,除了对称轴上的两个点,其余点都跟对面的点置换了,循环节的个数是k+1,
两个相邻点的中点和圆心的连线也是k条,每个点都跟对面的点置换了,循环节的个数是k,对称轴一共也是n条。
const int maxn = 30; LL pow3[maxn] = {1}; void init(){ FOR(i,1,maxn) pow3[i] = pow3[i-1] * 3; } int gcd(int x, int y){ if (!x || !y) return x + y; for (int t; t = x % y; x = y, y = t); return y; } int n, k; LL ans; void polya(){ ans = 0; k = n>>1; if(n&1) ans += n * pow3[k+1]; //翻转 else ans += k * (pow3[k+1] + pow3[k]); ans += pow3[n]; //旋转0 FOR(i,1,n){ //旋转i int t = gcd(i, n); ans += pow3[t]; } ans /= n<<1 ; cout<<ans<<endl; } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif init(); while( cin>>n, n != -1 ){ if( n == 0) {cout<<0<<endl;continue;} polya(); } return 0; }