polya定理

这就是所谓的polya定理。具体去百度文库看论文。

POJ 1286 Necklace of Beads

题意:用3种颜色给圆上n个点染色。问你有多少种染色方法。

做法:旋转有n个置换,对称也有n个置换。然后对于旋转,暴力找出循环节;对称,根据n是奇数还是偶数分开来求,循环节就根据对称来求。然后套上polya定理就好了

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <vector>
 7 #include <queue>
 8 
 9 using namespace std;
10 
11 #define LL long long
12 #define eps 1e-6
13 #define inf 0x3f3f3f3f
14 #define mod 1000
15 #define MP make_pair
16 #define mnx 50
17 
18 LL qpow( LL x, int k ){
19     LL ret = 1;
20     while( k ){
21         if( k & 1 ) ret *= x;
22         x *= x;
23         k >>= 1;
24     }
25     return ret;
26 }
27 int num[mnx], n;
28 bool vis[mnx];
29 void dfs( int u ){
30     vis[u] = 1;
31     int v = num[u];
32     if( !vis[v] )
33         dfs( v );
34 }
35 int gao( int s ){
36     memset( vis, 0, sizeof(vis) );
37     for( int i = 1; i <= n; ++i ){
38         num[i] = ( i + s - 1 ) % n + 1;
39     }
40     int ret = 0;
41     for( int i = 1; i <= n; ++i ){
42         if( !vis[i] )
43             dfs( i ), ret++;
44     }
45     return ret;
46 }
47 int main(){
48     while( scanf( "%d", &n ) != EOF && n != -1 ){
49         if( n == 0 ){
50             puts( "0" ); continue;
51         }
52         LL sum = 0;
53         for( int i = 0; i < n; ++i ){
54             int tmp = gao( i );
55             sum += qpow( 3LL, tmp );
56         }
57         if( n % 2 == 0 ){
58             sum += qpow( 3LL, (n+2)/2 ) * ( n/2 );
59             sum += qpow( 3LL, n/2 ) * ( n/2 );
60         }
61         else sum += qpow( 3LL, (n+1)/2 ) * n;
62         printf( "%I64d\n", sum / 2 / n );
63     }
64     return 0;
65 }
View Code

POJ 2409 Let it Bead

题意:c种颜色,手链有n个珠子,问你有多少种不同的染色方法。

做法:跟上题差不多。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <vector>
 7 #include <queue>
 8 
 9 using namespace std;
10 
11 #define LL long long
12 #define eps 1e-6
13 #define inf 0x3f3f3f3f
14 #define mod 1000
15 #define MP make_pair
16 #define mnx 50
17 
18 LL qpow( int x, int k ){
19     LL ret = 1;
20     while( k ){
21         if( k & 1 ) ret *= x;
22         x *= x;
23         k >>= 1;
24     }
25     return ret;
26 }
27 int n, num[mnx];
28 bool vis[mnx];
29 void dfs( int u ){
30     vis[u] = 1;
31     int v = num[u];
32     if( !vis[v] )
33         dfs( v );
34 }
35 int gao( int s ){
36     memset( vis, 0, sizeof( vis) );
37     for( int i = 1; i <= n; ++i )
38         num[i] = ( i + s - 1 ) % n + 1;
39     int ret =0;
40     for( int i = 1; i <= n; ++i ){
41         if( !vis[i] )
42             dfs( i ), ret++;
43     }
44     return ret;
45 }
46 int main(){
47     int c;
48     while( scanf( "%d%d", &c, &n ) != EOF && ( c || n ) ){
49         if( n == 0 ){
50             puts( "0" ); continue;
51         }
52         LL sum = 0;
53         for( int i = 0; i < n; ++i ){
54             int tmp = gao( i );
55             sum += qpow( c, tmp );
56         }
57         if( n % 2 )
58             sum += qpow( c, (n+1)/2 ) * n;
59         else{
60             sum += qpow( c, (n+2)/2 ) * ( n/2 );
61             sum += qpow( c, n/2 ) * ( n/2 );
62         }
63         printf( "%I64d\n", sum / 2 / n );
64     }
65     return 0;
66 }
View Code

HDU 1812 Count the Tetris

题意:n*n的棋盘有c种颜色来染色。问你有多少种不同的染色方法。

做法:旋转4种,对称4种,找出循环节就好了。得用java做。

 1 import java.math.*;
 2 import java.util.*;
 3 import java.io.*;
 4 
 5 public class Main{
 6     public static void main(String args[]){
 7         Scanner cin = new Scanner( System.in );
 8         while( cin.hasNext() ){
 9             int n = cin.nextInt();
10             BigInteger c = cin.nextBigInteger();
11             int c1 = n*n, c3 = ( n*n + 1 ) / 2, c2 = ( n*n + 3 ) / 4, c4 = c2, c5, c6, c7, c8;
12             if( n % 2 == 0 ){
13                 c5 = c7 = n*n / 2; c6 = c8 = ( n*n - n ) / 2 + n;
14             }
15             else{
16                 c5 = c6 = c7 = c8 = ( n*n - n ) / 2 + n; 
17             }
18             //System.out.println( c1 + " " + c2 + " " + c3 + " " + c4 );
19             //System.out.println( c5 + " " + c6 + " " + c7 + " " + c8 );
20             BigInteger eight = new BigInteger( "8" );
21             BigInteger ans = c.pow( c1 );
22             ans = ans.add( c.pow( c2 ) );
23             ans = ans.add( c.pow( c3 ) );
24             ans = ans.add( c.pow( c4 ) );
25             ans = ans.add( c.pow( c5 ) );
26             ans = ans.add( c.pow( c6 ) );
27             ans = ans.add( c.pow( c7 ) );
28             ans = ans.add( c.pow( c8 ) );
29             System.out.println( ans.divide( eight ) );
30         }
31     }
32 }
View Code

POJ 2154 Color

题意:项链有n个珠子,用n种颜色染色。只考虑旋转,不考虑对称,问有多少种不同的染色方法(答案% p )1  <= n <= 1000000000

做法:n很大,注意到gcd(n,i)就是旋转 i 个珠子的循环节。设len 为循环节的长度,则len = n / gcd( n, i );我们枚举len,则gcd( n, i ) = n/len; 我们想知道循环节为 n / len的有多少个,即gcd( n/(n/len), i/(n/len) ) = 1,即gcd( len, i/(n/len) = 1,即phi( len ),然后 ans += ( phi(len) * qpow( n, n/len ) ) % mod,因为ans最后要 / n,所以就qpow( n, n/len-1 );

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <vector>
 7 #include <queue>
 8 
 9 using namespace std;
10 
11 #define LL long long
12 #define eps 1e-6
13 #define inf 0x3f3f3f3f
14 #define MP make_pair
15 #define mnx 50005
16 
17 int pri[mnx], tot;
18 bool isnot[mnx];
19 void init(){
20     for( int i = 2; i < mnx; ++i ){
21         if( !isnot[i] ){
22             pri[tot++] = i;
23         }
24         for( int j = 0; j < tot && i * pri[j] < mnx; ++j ){
25             isnot[i*pri[j]] = 1;
26             if( i % pri[j] == 0 )
27                 break;
28         }
29     }
30 }
31 int phi( int x ){
32     int ret = x;
33     for( int i = 0; i < tot && pri[i] * pri[i] <= x; ++i ){
34         if( x % pri[i] == 0 )
35             ret = ret / pri[i] * ( pri[i] - 1 );
36         while( x % pri[i] == 0 )
37             x /= pri[i];
38     }
39     if( x > 1 ) ret = ret / x * ( x - 1 );
40     return ret;
41 }
42 int mod;
43 int qpow( int x, int k ){
44     int ret = 1;
45     x %= mod;
46     while( k ){
47         if( k & 1 ) ret = ret * x % mod;
48         x = x * x % mod;
49         k >>= 1;
50     }
51     return ret;
52 }
53 int n;
54 void solve(){
55     int sum = 0;
56     int i;
57     for( i = 1; i * i < n; ++i ){
58         if( n % i == 0 ){
59             int tmp = n / i;
60             sum = ( sum + phi(i) % mod * qpow( n, tmp-1 ) % mod ) % mod;
61             sum = ( sum + phi(tmp) % mod * qpow( n, i-1 ) % mod ) % mod;
62         }
63     }
64     if( i * i == n )
65         sum = ( sum + phi(i) * qpow( n, i-1 ) % mod ) % mod;
66     printf( "%d\n", sum );
67 }
68 int main(){
69     int cas;
70     init();
71     scanf( "%d", &cas );
72     while( cas-- ){
73         scanf( "%d%d", &n, &mod );
74         solve();
75     }
76     return 0;
77 }
View Code

UVA 11255 Necklace

题意:有a,b,c三种颜色的珠子,问你用这三种颜色的珠子,组成n = a + b + c的项链有多少种方法。

做法:旋转有n种,循环节是gcd( n, i )。对称的时候分奇数和偶数的情况。奇数情况,关于某个珠子对称,这个珠子可能是a或者b或者c的颜色,循环节长度为2,有n种情况。偶数的时候,关于两个珠子对称的时候,如果对称的珠子是不同颜色,那么有n种情况;对称的珠子同种颜色,有n/2种情况;不是关于珠子对称,而是关于对边的中点对称,有n/2种情况。因为颜色有限制,所以得用组合数计算。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <vector>
 7 #include <queue>
 8 
 9 using namespace std;
10 
11 #define LL long long
12 #define eps 1e-6
13 #define inf 0x3f3f3f3f
14 #define MP make_pair
15 #define mnx 42
16 
17 LL C[mnx][mnx];
18 void init(){
19     for( int i = 0; i < mnx; ++i ){
20         C[i][0] = C[i][i] = 1;
21         for( int j = 1; j < i; ++j )
22             C[i][j] = C[i-1][j] + C[i-1][j-1];
23     }
24 }
25 int gcd( int a, int b ){
26     return b == 0 ? a : gcd( b, a % b );
27 }
28 LL calc( int a, int b, int c, int len, int m ){
29     if( a < 0 || b < 0 || c < 0 ) return 0;
30     if( a % len || b % len || c % len ) return 0;
31     a /= len, b /= len;
32     return C[m][a] * C[m-a][b];
33 }
34 int main(){
35     int cas;
36     init();
37     scanf( "%d", &cas );
38     while( cas-- ){
39         int a, b, c, n;
40         scanf( "%d%d%d", &a, &b, &c );
41         n = a + b + c;
42         LL sum = 0;
43         for( int i = 0; i < n; ++i ){
44             int tmp = gcd( n, i );
45             sum += calc( a, b, c, n/tmp, tmp );
46         }
47         if( n % 2 ){
48             sum += calc( a-1, b, c, 2, n/2 ) * n;
49             sum += calc( a, b-1, c, 2, n/2 ) * n;
50             sum += calc( a, b, c-1, 2, n/2 ) * n;
51         }
52         else{
53             sum += calc( a, b, c, 2, n/2 ) * n / 2;
54             sum += calc( a-1, b-1, c, 2, (n-2)/2 ) * n;
55             sum += calc( a-1, b, c-1, 2, (n-2)/2 ) * n;
56             sum += calc( a, b-1, c-1, 2, (n-2)/2 ) * n;
57             sum += calc( a-2, b, c, 2, (n-2)/2 ) * n / 2;
58             sum += calc( a, b-2, c, 2, (n-2)/2 ) * n / 2;
59             sum += calc( a, b, c-2, 2, (n-2)/2 ) * n / 2;
60         }
61         printf( "%lld\n", sum / 2 / n );
62     }
63     return 0;
64 }
View Code

UVA 10601 Cubes

题意:有12条边,每条边的颜色不定,问你有多少种方法组成一个正方体。

做法:总共有24个置换。不动时候1种,循环节是12,循环节长度是1。绕对面的中心的连线旋转90度,180度,270度,有3组连线,总共9种情况:绕90度,270度的时候,循环节是3,循环节长度是4。绕对顶点的连线旋转120度,240度,有4组对顶点,总共8种情况,旋转的时候循环节都是4,循环节长度是3。绕对棱旋转180度,有6组对棱,共6种情况,注意到有一组对棱在旋转的时候是不变的,因此循环节是7,然后枚举这组对棱涂的颜色,剩下的再进行calc。最后ans/24

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <vector>
 7 #include <queue>
 8 
 9 using namespace std;
10 
11 #define LL long long
12 #define eps 1e-6
13 #define inf 0x3f3f3f3f
14 #define mod 1000
15 #define MP make_pair
16 #define mnx 15
17 
18 LL C[mnx][mnx];
19 void init(){
20     for( int i = 0; i < mnx; ++i ){
21         C[i][0] = C[i][i] = 1;
22         for( int j = 1; j < i; ++j )
23             C[i][j] = C[i-1][j] + C[i-1][j-1];
24     }
25 }
26 int a[mnx], b[mnx];
27 LL calc( int len, int m ){
28     for( int i = 1; i <= 6; ++i ){
29         if( b[i] % len || b[i] < 0 )
30             return 0;
31         b[i] /= len;
32     }
33     LL ret = 1;
34     for( int i = 1; i <= 6; ++i ){
35         ret *= C[m][b[i]];
36         m -= b[i];
37     }
38     return ret;
39 }
40 void solve(){
41     LL sum = 0;
42     memcpy( b, a, sizeof(a) );
43     sum += calc( 1, 12 );
44     memcpy( b, a, sizeof(a) );
45     sum += calc( 4, 3 ) * 6;
46     memcpy( b, a, sizeof(a) );
47     sum += calc( 2, 6 ) * 3;
48     memcpy( b, a, sizeof(a) );
49     sum += calc( 3, 4 ) * 8;
50     for( int i = 1; i <= 6; ++i ){
51         for( int j = i; j <= 6; ++j ){
52             memcpy( b, a, sizeof(a) );
53             b[i]--, b[j]--;
54             if( i != j )
55                 sum += calc( 2, 5 ) * 12;
56             else
57                 sum += calc( 2, 5 ) * 6;
58         }
59     }
60     printf( "%lld\n", sum / 24 );
61 }
62 int main(){
63     int cas;
64     init();
65     scanf( "%d", &cas );
66     while( cas-- ){
67         memset( a, 0, sizeof(a) );
68         for( int i = 0; i < 12; ++i ){
69             int c;
70             scanf( "%d", &c );
71             a[c]++;
72         }
73         solve();
74     }
75 }
View Code

POJ 2888 Magic Bracelet

题意:有n个珠子组成的手链,有m种颜色的珠子( m <= 10 ),有k个限定的条件(颜色a不能和颜色b相连)。问你有多少种方法组成不同的手链。

做法:初始化矩阵g全部为1,对于限定条件,g[a][b] = 0。然后对于循环节为 tmp 时,计算颜色矩阵经过 tmp 次循环后sigma g[i][i]就是在该置换下着色方案的不动置换的个数。因为有mod,所以最后的时候不能/n,而是取逆元。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <vector>
  7 #include <queue>
  8 
  9 using namespace std;
 10 
 11 #define LL long long
 12 #define eps 1e-6
 13 #define inf 0x3f3f3f3f
 14 #define MP make_pair
 15 #define mnx 50005
 16 #define mod 9973
 17 
 18 int pri[mnx], tot;
 19 bool isnot[mnx];
 20 void init(){
 21     for( int i = 2; i < mnx; ++i ){
 22         if( !isnot[i] ){
 23             pri[tot++] = i;
 24         }
 25         for( int j = 0; j < tot && i * pri[j] < mnx; ++j ){
 26             isnot[i*pri[j]] = 1;
 27             if( i % pri[j] == 0 )
 28                 break;
 29         }
 30     }
 31 }
 32 int phi( int x ){
 33     int ret = x;
 34     for( int i = 0; i < tot && pri[i] * pri[i] <= x; ++i ){
 35         if( x % pri[i] == 0 )
 36             ret = ret / pri[i] * ( pri[i] - 1 );
 37         while( x % pri[i] == 0 )
 38             x /= pri[i];
 39     }
 40     if( x > 1 ) ret = ret / x * ( x - 1 );
 41     return ret % mod;
 42 }
 43 int n, m;
 44 struct Matrix{
 45     int g[12][12];
 46     Matrix operator * ( const Matrix &b ) const {
 47         Matrix ret;
 48         memset( ret.g, 0, sizeof(ret.g) );
 49         for( int i = 1; i <= m; ++i )
 50             for( int j = 1; j <= m; ++j ){
 51                 for( int k = 1; k <= m; ++k )
 52                     ret.g[i][j] += g[i][k] * b.g[k][j];  //要是ret.g[i][j] = ( g[i][k] * b.g[k][j] + ret.g[i][j] ) % mod
 53                 ret.g[i][j] %= mod;                      //这样会慢很多,c++会tle,g++才能过。因为%mod比较耗时间
 54             }
 55         return ret;
 56     }
 57 };
 58 Matrix qpow( Matrix x, int k ){
 59     Matrix ret;
 60     memset( ret.g, 0, sizeof(ret.g) );
 61     for( int i = 1; i <= m; ++i )
 62         ret.g[i][i] = 1;
 63     while( k ){
 64         if( k & 1 ) ret = ret * x;
 65         x = x * x;
 66         k >>= 1;
 67     }
 68     return ret;
 69 }
 70 int qpow( int x, int k ){
 71     int ret = 1;
 72     x %= mod;
 73     while( k ){
 74         if( k & 1 ) ret = ret * x % mod;
 75         x = x * x % mod;
 76         k >>= 1;
 77     }
 78     return ret;
 79 }
 80 int k;
 81 Matrix a;
 82 int gao( int x ){
 83     int res = 0;
 84     Matrix ret = qpow( a, x );
 85     for( int i = 1; i <= m; ++i )
 86         res += ret.g[i][i];
 87     return res % mod;
 88 }
 89 void solve(){
 90     int ans = 0;
 91     int i;
 92     for( i = 1; i * i < n; ++i ){
 93         if( n % i == 0 ){
 94             int tmp = n / i;
 95             ans = ( ans + phi(tmp) * gao(i) ) % mod;
 96             ans = ( ans + phi(i) * gao(tmp) ) % mod;
 97         }
 98     }
 99     if( i * i == n )
100         ans = ( ans + phi(i) * gao(i) ) % mod;
101     int inv = qpow( n % mod, mod - 2 ) % mod;
102     ans = ( ans * inv ) % mod;
103     printf( "%d\n", ans );
104 }
105 int main(){
106     freopen( "tt.txt", "r", stdin );
107     int cas;
108     init();
109     scanf( "%d", &cas );
110     while( cas-- ){
111         scanf( "%d%d%d", &n, &m, &k );
112         for( int i = 1; i <= m; ++i )
113             for( int j = 1; j <= m; ++j )
114                 a.g[i][j] = 1;
115         for( int i = 0; i < k; ++i ){
116             int u, v;
117             scanf( "%d%d", &u, &v );
118             a.g[u][v] = a.g[v][u] = 0;
119         }
120         solve();
121     }
122     return 0;
123 }
View Code

 

posted @ 2015-04-03 12:01  L__J  阅读(471)  评论(0编辑  收藏  举报