题意:m种珠子串成由n个珠子构成的环,并且有一些限制,比如第i种与第j种不能相邻,旋转后相同算是同一种方案,求方案数。(m<=10,n<=10^9)

如果没有限制条件,可以很容易用Burnside定理+容斥得到答案。

如果只考虑限制,观察发现,m很小,n很大。那么可以通过快速幂得到从第i种到第j种,共有k个珠子的方案数。

再回到Burnside定理,显然有n种置换,现在问题是如何求每种置换能保持不变的着色方案数:

【POJ】2154 Color已经推出,第i种置换(即旋转360/n*i度)会有GCD(n,i)种不同的颜色,循环节长度为GCD(n,i)。

就可以用快速幂得到从第i种回到第i种,共有GCD(n,i)个珠子的方案数。带回Burnside定理+容斥,问题就解决了。

【POJ】2409 Let it Bead->【POJ】2154 Color->【POJ】2888 Magic Bracelet

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<vector>
  5 #define P 9973
  6 #define EPS 1e-8
  7 #define MAXN 12
  8 #define MAXM 32000
  9 using namespace std;
 10 int n, m;
 11 bool p[MAXM];
 12 vector<int> prime;
 13 vector<int> factor;
 14 vector<int> primefactor;
 15 struct Matrix {
 16     int mat[MAXN][MAXN];
 17     void Zero() {
 18         memset(mat, 0, sizeof(mat));
 19     }
 20     void Unit() {
 21         int i;
 22         for (i = 0; i < MAXN; i++)
 23             mat[i][i] = 1;
 24     }
 25 } g;
 26 Matrix operator *(Matrix &a, Matrix &b) {
 27     Matrix tmp;
 28     int i, j, k;
 29     tmp.Zero();
 30     for (k = 0; k < m; k++) {
 31         for (i = 0; i < m; i++) {
 32             if (a.mat[i][k] == 0)
 33                 continue;
 34             for (j = 0; j < m; j++) {
 35                 tmp.mat[i][j] += a.mat[i][k] * b.mat[k][j] % P;
 36                 if (tmp.mat[i][j] >= P)
 37                     tmp.mat[i][j] -= P;
 38             }
 39         }
 40     }
 41     return tmp;
 42 }
 43 Matrix operator ^(Matrix a, int k) {
 44     Matrix tmp;
 45     tmp.Zero();
 46     tmp.Unit();
 47     for (; k; k >>= 1) {
 48         if (k & 1)
 49             tmp = tmp * a;
 50         a = a * a;
 51     }
 52     return tmp;
 53 }
 54 void Init() {
 55     int i, j;
 56     prime.clear();
 57     memset(p, true, sizeof(p));
 58     for (i = 2; i < 180; i++) {
 59         if (p[i]) {
 60             for (j = i * i; j < MAXM; j += i)
 61                 p[j] = false;
 62         }
 63     }
 64     for (i = 2; i < MAXM; i++) {
 65         if (p[i])
 66             prime.push_back(i);
 67     }
 68 }
 69 int ExtGcd(int a, int b, int &x, int &y) {
 70     int t, d;
 71     if (b == 0) {
 72         x = 1;
 73         y = 0;
 74         return a;
 75     }
 76     d = ExtGcd(b, a % b, x, y);
 77     t = x;
 78     x = y;
 79     y = t - a / b * y;
 80     return d;
 81 }
 82 int Invmod(int a, int n) {
 83     int x, y;
 84     ExtGcd(a, n, x, y);
 85     return (x % n + n) % n;
 86 }
 87 void Factor(int x) {
 88     int i, tmp;
 89     factor.clear();
 90     tmp = (int) (sqrt((double) x) + EPS);
 91     for (i = 1; i <= tmp; i++) {
 92         if (x % i == 0) {
 93             factor.push_back(i);
 94             if (i == tmp && i * i == x)
 95                 continue;
 96             factor.push_back(n / i);
 97         }
 98     }
 99 }
100 int NoChange(int x) {
101     int i, ans;
102     Matrix tmp;
103     tmp = g ^ x;
104     for (i = ans = 0; i < m; i++) {
105         ans += tmp.mat[i][i];
106         if (ans >= P)
107             ans -= P;
108     }
109     return ans;
110 }
111 void Prime(int x) {
112     int i, tmp;
113     primefactor.clear();
114     tmp = (int) (sqrt((double) x) + EPS);
115     for (i = 0; prime[i] <= tmp; i++) {
116         if (x % prime[i] == 0) {
117             primefactor.push_back(prime[i]);
118             while (x % prime[i] == 0)
119                 x /= prime[i];
120         }
121     }
122     if (x > 1)
123         primefactor.push_back(x);
124 }
125 int Mul(int x, int &k) {
126     int i, ans;
127     ans = 1;
128     for (i = k = 0; x; x >>= 1, i++) {
129         if (x & 1) {
130             k++;
131             ans *= primefactor[i];
132         }
133     }
134     return ans;
135 }
136 int Count(int x) {
137     int i, j, t, ans, tmp;
138     Prime(x);
139     ans = 0;
140     t = (int) primefactor.size();
141     for (i = 1; i < (1 << t); i++) {
142         tmp = Mul(i, j);
143         if (j & 1)
144             ans += x / tmp;
145         else
146             ans -= x / tmp;
147     }
148     return (x - ans) % P;
149 }
150 int Burnside() {
151     int i, ans;
152     Factor(n);
153     for (i = ans = 0; i < (int) factor.size(); i++) {
154         ans += Count(n / factor[i]) * NoChange(factor[i]) % P;
155         if (ans >= P)
156             ans -= P;
157     }
158     return ans * Invmod(n, P) % P;
159 }
160 int main() {
161     int c;
162     int i, j, k, x, y;
163     Init();
164     scanf("%d", &c);
165     while (c--) {
166         scanf("%d%d%d", &n, &m, &k);
167         g.Zero();
168         for (i = 0; i < m; i++) {
169             for (j = 0; j < m; j++)
170                 g.mat[i][j] = 1;
171         }
172         while (k--) {
173             scanf("%d%d", &x, &y);
174             x--, y--;
175             g.mat[x][y] = g.mat[y][x] = 0;
176         }
177         printf("%d\n", Burnside());
178     }
179     return 0;
180 }
posted on 2012-09-11 14:43  DrunBee  阅读(1152)  评论(0编辑  收藏  举报