第一题Polya计数,好有意思的定理。
题目输入很简单,就是一个n,问n个在环上等距放置的球,可以用3种颜色染色,用各种方式(旋转/翻转)去除重复染色方案后,输出总染色方案数。
看完Polya定理后,结合题目条件想了一下便推出了解:
若另某个位置为0,顺时针方向依次为位置0、1、……、n-1,那么,可以分别另0号球于0、1、……、n-1开始,沿顺时/逆时针方向依次摆下其余编号的球,那么总共有2n种不同的置换方案的,这也是覆盖了全部置换的情况。接下来便是对每种置换方案计算各自的轮换数了,这步也很简单的,对每个不在自己位置且未标记的球迭代求对应的轮换,每次找到新的轮换都将对应方案的轮换数增一即可。最后sum(pow(3,ci))/2n便是结果了。
本来以为可以1A的。。。结果没考虑n=0的情况。。。还是太嫩了。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include<cstdio> #include<cstring> #include<cmath> int n,p[24],b[24],c[46]; long long d; int main() { int i,j,k,l,cl; while(~scanf("%d",&n)&&~n) { memset(c,0,sizeof c); for(i=cl=0;i<n;i++) { for(k=i,l=0;k<n;k++,l++) p[k]=l; for(k=0;l<n;k++,l++) p[k]=l; memset(b,0,sizeof b); for(k=0;k<n;k++) { if(b[k]) continue; c[cl]++; for(l=k;!b[l];l=p[l]) b[l]=1; } cl++; for(k=i,l=0;k>-1;k--,l++) p[k]=l; for(k=n-1;l<n;k--,l++) p[k]=l; memset(b,0,sizeof b); for(k=0;k<n;k++) { if(b[k]) continue; c[cl]++; for(l=k;!b[l];l=p[l]) b[l]=1; } cl++; } for(i=0,d=0;i<cl;i++) d+=pow(3,c[i]); if(!n) puts("0"); else printf("%lld\n",d/(n*2)); } return 0; } |
但即使AC了也只是略微明白定理如何使用,证明看了一下发现不太好懂,就暂时放下了。