题目:http://poj.org/problem?id=2888
题意:给定n(n <= 10^9)颗珠子,组成一串项链,每颗珠子可以用m种颜色中一种来涂色,如果两种涂色方法通过旋转项链可以得到视为等价。
然后再给定K组限制,每组限制a、b代表颜色a和颜色b不能涂在相邻的珠子上面。问一共有多少种涂色方法。
思路: 如果这题没有后面的限制,就和 poj 2154 一样了:http://www.cnblogs.com/jian1573/p/3234627.html
现在我们要处理的就是 K 种限制, 可以用DP求解。 i为珠子编号, c为颜色编号那么:dp[i][c]=∑dp[i-1][cc] cc 为可以与 c 相邻的颜色编号;
由于N为 1e9 O(N) 会TLE, 所以我们可以用矩阵快速幂来优化为O(lgN):具体用m[i][j]=1,表示合法, m[i][j]=0表示不合法,
那么m^k后的对角线上的元素和即为所求。
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 const int Mod=9973; 7 int N, M, K, T; 8 struct Mar 9 { 10 int m[15][15]; 11 inline void zero( ){ 12 memset(m, 0, sizeof m); 13 } 14 inline void one( ){ 15 zero( ); 16 for( int i=0; i<M; ++i ){ 17 for( int j=0; j<M; ++j ){ 18 m[i][j]=1; 19 } 20 } 21 } 22 inline void unit( ){ 23 zero(); 24 for( int i=0; i<M; ++ i ) 25 m[i][i]=1; 26 } 27 inline Mar operator *(const Mar &a) const { 28 Mar C;C.zero(); 29 for( int i=0; i<M; ++i ){ 30 for(int j=0; j<M; ++j ){ 31 for( int k=0; k<M; ++k ){ 32 C.m[i][j]+=m[i][k]*a.m[k][j]; 33 C.m[i][j]%=Mod; 34 } 35 } 36 } 37 return C; 38 } 39 inline Mar operator ^ (int t) const{ 40 Mar B=*this, C; 41 C.unit( ); 42 while(t){ 43 if(t&1)C=C*B; 44 B=B*B; 45 t>>=1; 46 } 47 return C; 48 } 49 }A; 50 int a[100005], p[10005],cntp=0; 51 void getp( ) 52 { 53 for( int i=2; i<=1e5; ++ i ){ 54 if( !a[i] )p[cntp++]=i; 55 for( int j=0; j<cntp&&i*p[j]<1e5; ++ j ){ 56 a[i*p[j]]=1; 57 if( i%p[j]==0 )break; 58 } 59 } 60 } 61 62 int Phi( int x ) 63 { 64 int res=x; 65 for( int i=0; i<cntp&&p[i]*p[i]<=x; ++i ){ 66 if( x%p[i]==0 ){ 67 res/=p[i]; res*=(p[i]-1); 68 while(x%p[i]==0){ 69 x/=p[i]; 70 } 71 } 72 } 73 if(x>1){ 74 res/=x;res*=(x-1); 75 } 76 return res%Mod; 77 } 78 int P_M(int a, int b) 79 { 80 int res=1; 81 while(b){ 82 if(b&1)res*=a, res%=Mod; 83 a*=a, a%=Mod; 84 b>>=1; 85 } 86 return res; 87 88 } 89 int work( int k ) 90 { 91 Mar C=A^k; 92 int res=0; 93 for( int i=0; i<M; ++i ) 94 res+=C.m[i][i]; 95 return res; 96 } 97 int polya( ) 98 { 99 int ans=0; 100 for( int i=1; i*i<=N; ++ i ){ 101 if( N%i==0 ){ 102 if(i*i==N){ 103 ans+=Phi(i)*work(i); 104 ans%=Mod; 105 } 106 else{ 107 ans+=Phi(i)*work(N/i); 108 ans%=Mod; 109 ans+=Phi(N/i)*work(i); 110 ans%=Mod; 111 } 112 } 113 } 114 return ans; 115 } 116 int main( ) 117 { 118 getp(); 119 scanf("%d", &T); 120 while (T--){ 121 scanf("%d%d%d", &N, &M, &K); 122 A.one(); 123 for( int i=0, x, y; i<K; ++i ){ 124 scanf("%d%d", &x, &y); 125 A.m[x-1][y-1]=A.m[y-1][x-1]=0; 126 } 127 int ans=polya(); 128 int inv=P_M(N%Mod, Mod-2); 129 ans*=inv;ans%=Mod; 130 printf("%d ", ans); 131 } 132 return 0; 133 }