题意:一个圆上有n个点,用不同的角度表示,用k种颜色对n个点着色,旋转后相同视为同一种着色方案,问着色方案数。
举几个例子:
0 90000 180000 270000,每次旋转90度,每个点都能重合。
0 45000 90000 180000 270000,无论怎么旋转,都不能重合。
30000 150000 180000 330000,旋转180度才能重合。
如何判断在旋转360度之内,能重合几次。
将两个连续的点之间的角度差值处理出来,最多循环t次,那么有t个旋转使得重合。这可以用到next数组的性质。
设当前得到a个循环,每个循环b个点。
那么可以把b个点看成一个点,那么问题转化为a个点构成的环,着k^b种颜色,旋转后相同视为同一种着色方案,问着色方案数。
就和这题等价了:【POJ】2154 Color。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 #define MAXN 360010 6 #define S 360000 7 #define P 100000007 8 typedef long long LL; 9 using namespace std; 10 int dg[MAXN], str[MAXN], next[MAXN], phi[MAXN]; 11 vector<int> factor; 12 LL PowMod(LL a, LL b, LL c) { 13 LL ans; 14 a %= c; 15 for (ans = 1; b; b >>= 1) { 16 if (b & 1) { 17 ans *= a; 18 ans %= c; 19 } 20 a *= a; 21 a %= c; 22 } 23 return ans; 24 } 25 int NEXT(int n) { 26 int i, j; 27 next[0] = j = -1; 28 for (i = 0; i < n;) { 29 if (j < 0 || str[i] == str[j]) { 30 i++; 31 j++; 32 next[i] = j; 33 } else 34 j = next[j]; 35 } 36 i = n - j; 37 if (n % i) 38 return n; 39 return i; 40 } 41 LL ExtGcd(LL a, LL b, LL &x, LL &y) { 42 LL t, d; 43 if (b == 0) { 44 x = 1; 45 y = 0; 46 return a; 47 } 48 d = ExtGcd(b, a % b, x, y); 49 t = x; 50 x = y; 51 y = t - a / b * y; 52 return d; 53 } 54 LL InvMod(LL a, LL n) { 55 LL x, y; 56 ExtGcd(a, n, x, y); 57 return (x % n + n) % n; 58 } 59 void Factor(int n) { 60 int i; 61 factor.clear(); 62 for (i = 1; i * i <= n; i++) { 63 if (n % i == 0) { 64 factor.push_back(i); 65 if (i * i == n) 66 continue; 67 factor.push_back(n / i); 68 } 69 } 70 } 71 LL Burnside(int n, int k) { 72 int i; 73 LL ans; 74 Factor(n); 75 for (ans = i = 0; i < (int) factor.size(); i++) { 76 ans += PowMod(k, factor[i], P) * phi[n / factor[i]] % P; 77 if (ans >= P) 78 ans -= P; 79 } 80 return (ans * InvMod(n, P)) % P; 81 } 82 void Init() { 83 int i, j; 84 memset(phi, 0, sizeof(phi)); 85 phi[1] = 1; 86 for (i = 2; i < MAXN; i++) { 87 if (!phi[i]) { 88 for (j = i; j < MAXN; j += i) { 89 if (!phi[j]) 90 phi[j] = j; 91 phi[j] -= phi[j] / i; 92 } 93 } 94 } 95 } 96 int main() { 97 int k, n, i, len; 98 Init(); 99 while (scanf("%d%d", &k, &n), k != -1 || n != -1) { 100 for (i = 0; i < n; i++) 101 scanf("%d", &dg[i]); 102 sort(dg, dg + n); 103 for (i = 1; i < n; i++) 104 str[i] = dg[i] - dg[i - 1]; 105 str[0] = S - dg[n - 1] + dg[0]; 106 len = NEXT(n); 107 printf("%I64d\n", Burnside(n / len, PowMod(k, len, P))); 108 } 109 return 0; 110 }