http://acm.hdu.edu.cn/showproblem.php?pid=3869

polya计数

题里给的环,可以从某个顶点开始,按照逆时针顺序,依次将经过的边权和点权构成一个序列,那么这个序列唯一确定这个环。并且,一切旋转,都相当于对形成的序列进行循环移位。因此可以用扩展KMP算法,将两个原序列拼接作为匹配串,将原序列作为模式串,就可以在O(N)内知道所有能和原串重合的移位方法。对于每个移位方法,对应于一种旋转。最后使用polya进行计数,对于每种旋转重合的k,其对应循环节长度为gcd(N,k)。最后公式就是对所有能旋转k次重合的k,result=sigma( C^gcd(N,k) )/(k的种类数)。

  1 /**/ /*
  2    author: AmazingCaddy
  3    time:    2011/8/10   21:11
  4*/

  5 #include  < cstdio >
  6 #include  < complex >
  7 #include  < cstdlib >
  8 #include  < iostream >
  9 #include  < cstring >
 10 #include  < string >
 11 #include  < algorithm >
 12 #include  < cmath >
 13 #include  < ctime >
 14 #include  < vector >
 15 #include  < map >
 16 #include  < queue >
 17 using   namespace  std;
 18
 19 // typedef __int64 ll;
 20 typedef  long   long  ll;
 21
 22 const   int  mod  =   1000000007 ;
 23 const   int  maxn  =   100004 ;
 24
 25 struct  node
 26 {
 27    int vec, edge;
 28    bool operator == ( const node & a ) const
 29    {
 30        return vec == a.vec && edge == a.edge;
 31    }

 32    bool operator != ( const node & a ) const
 33    {
 34        return !*this == a );
 35    }

 36}
;
 37 node pattern[ maxn ], text[ maxn  <<   1  ];
 38
 39 ll powC[ maxn ];
 40 int  fail[ maxn ], vis[ maxn ];
 41 int  N, C;
 42
 43 ll gcd( ll a, ll b )  return ( b ? gcd( b, a % b ) : a ); }
 44
 45 ll pow_mod( ll a, ll b )
 46 {
 47    ll ans = 1, d = a % mod;
 48    while( b )
 49    {
 50        if( b & 1 ) ans = ans * d % mod;
 51        d = d * d % mod;
 52        b >>= 1;
 53    }

 54    return ans;
 55}

 56
 57 ll Inv( ll n )  return pow_mod( n, mod - 2 ); }
 58
 59 void  init( )
 60 {
 61    powC[ 0 ] = 1;
 62    forint i = 1; i <= N; i++ )
 63        powC[ i ] = powC[ i - 1 ] * C % mod;
 64}

 65
 66 void  faillink( )
 67 {
 68    node * t = pattern;
 69    --t;
 70    forint i = 1, j = 0; i <= N; i++, j++ )
 71    {
 72        fail[ i ] = j;
 73        while( j > 0 && t[ i ] != t[ j ] ) j = fail[ j ];
 74    }

 75    /**//*
 76    int j, k;
 77    flink[ 0 ] = -1;
 78    j = 1;
 79    while( j < N )
 80    {
 81        k = flink[ j - 1 ];
 82        while( k != -1 && pattern[ k ] != pattern[ j - 1 ] )
 83            k = flink[ k ];
 84        flink[ j ] = k + 1;
 85        j++;
 86    }
 87    */

 88}

 89
 90 void  kmp( )
 91 {
 92    node *= text, *= pattern;
 93    --s, --t;
 94    forint i = 1, j = 1; i <= 2 * N; i++, j++ )
 95    {
 96        while( j > 0 && s[ i ] != t[ j ] ) j = fail[ j ];
 97        if( j == N ) { vis[ i - N ] = 1; j = fail[ j ]; }
 98    }

 99    /**//*
100    int i = 0, j = 0;
101    while( i < N * 2 )
102    {
103        while( j != -1 && pattern[ j ] != text[ i ] )
104            j = flink[ j ];
105        if( j == N - 1 ) { vis[ i - N + 1 ] = 1; j = flink[ j ]; }
106        i++;
107        j++;
108    }
109    */

110}

111
112 int  main( int  argc,  char   * argv[])
113 {
114//    freopen( "in", "r", stdin );
115//    freopen( "out1", "w", stdout );
116    int cas;
117    scanf( "%d"&cas );
118    while( cas -- )
119    {
120        scanf( "%d%d"&N, &C );
121        init( );
122        forint i = 0; i < N; i++ )
123            scanf( "%d"&pattern[ i ].vec );
124        forint i = 0; i < N; i++ )
125            scanf( "%d"&pattern[ i ].edge );
126        forint i = 0; i < N; i++ )
127            text[ i ] = text[ i + N ] = pattern[ i ];
128        faillink( );
129        memset( vis, 0sizeof( vis ) );
130        kmp( );
131        ll ans = 0, cnt = 0;
132        forint i = 1; i <= N; i++ )
133        {
134            if( vis[ i ] )
135            {
136                cnt++;
137                ans = ( ans + powC[ gcd( N, i ) ] ) % mod;
138            }

139        }

140        ans = ans * Inv( cnt ) % mod;
141        cout << ans << "\n";
142    }

143//    cerr << clock( ) << endl;
144    return 0;
145}

146