【POJ】2409 Let it Bead

题意:用k种颜色对n个珠子构成的环上色,旋转翻转后相同的只算一种,求不等价的着色方案数。

Burnside定理的应用:

当n为奇数时,有n种翻转,每种翻转都是以一个顶点和该顶点对边的中点对称。有k^(n/2+1)*n种。

当n为偶数时,有n种翻转,其中一半是以两个对应顶点,另一半是以两条对边对称。有k^(n/2+1)*n/2+k^(n/2)*n/2种。

考虑旋转:枚举旋转角度360/n*i,(0<i<=n),也就是一个置换。经过该置换,颜色仍保持不变的着色方案有k^GCD(n,i)种。

 

一个长度为n的环,每i个上同一种颜色,可以上多少种颜色。

假设起点在x,则x,x+i,x+2*i,……,x+k*i,……

假设在第t次,第一次回到起点,则x=(x+t*i)%n => t*i%n=0 => t=LCM(i,n)/i=n*i/GCD(n,i)/i=n/GCD(n,i)。

那么可以上n/t种颜色,即n/(n/GCD(n,i))种,所以旋转的着色方案有k^GCD(n,i)种。

 1 #include<cstdio>

 2 typedef long long LL;

 3 LL Pow(LL a, LL b) {

 4     LL ans;

 5     for (ans = 1; b; b >>= 1) {

 6         if (b & 1)

 7             ans *= a;

 8         a *= a;

 9     }

10     return ans;

11 }

12 int GCD(int x, int y) {

13     return y ? GCD(y, x % y) : x;

14 }

15 int main() {

16     int n, k, i;

17     LL ans;

18     while (scanf("%d%d", &k, &n), n || k) {

19         if (n & 1)

20             ans = Pow(k, n / 2 + 1) * n;

21         else

22             ans = Pow(k, n / 2 + 1) * (n / 2)

23                     + Pow(k, n / 2) * (n / 2);

24         for (i = 1; i <= n; i++)

25             ans += Pow(k, GCD(n, i));

26         ans = printf("%lld\n", ans / (2 * n));

27     }

28     return 0;

29 }

你可能感兴趣的:(poj)