【POJ】2888 Magic Bracelet

题意: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 }

你可能感兴趣的:(poj)