zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
  • 相关阅读:
    Golang进阶实战之IO操作
    动态获取输入框光标在页面中的位置! || 动态添加 style标签 || 获取元素样式 || 获取元素在页面中的位置
    v-select插件
    各种创建数组的方法
    百度UEditor编辑器
    vue-router 各种守卫以及流程梳理
    Snipaste 一款好用的 windows截图工具
    ant-design-vue
    罕见的css样式
    vue图片点击放大预览v-viewer
  • 原文地址:https://www.cnblogs.com/LJ-blog/p/4389647.html
Copyright © 2011-2022 走看看