题意:n个珠子的环,之多着n种颜色,考虑旋转,不考虑翻转。问模P的方案数。
运用Burnside定理,有n个置换,每个置换使得着色不变的着色个数有GCD(n,i)个。
GCD(n,i)个的原因:【POJ】2409 Let it Bead
由于n达到十亿,显然不能枚举。但是可以发现,GCD(n,i)即n约数的个数很少。
问题转化为1~n有多少个数,使得GCD(n,i)=k。其中k是n的约数。这个问题等价于与n/k互质的个数有多少,那么容斥就能搞定。
由于有模P,Burnside定理最后要除以n,但是n与P不一定互质,可能没有逆元。观察到分子,不妨先都除以n,就避免了这个问题。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<vector> 5 #define EPS 1e-8 6 #define MAXN 32000 7 using namespace std; 8 vector<int> fac; 9 vector<int> g; 10 vector<int> prime; 11 int P; 12 bool p[MAXN]; 13 void Init() { 14 int i, j; 15 memset(p, true, sizeof(p)); 16 for (i = 2; i < 180; i++) { 17 if (p[i]) { 18 for (j = i * i; j < MAXN; j += i) 19 p[j] = false; 20 } 21 } 22 prime.clear(); 23 for (i = 2; i < MAXN; i++) { 24 if (p[i]) 25 prime.push_back(i); 26 } 27 } 28 void Factor(int n) { 29 int i, tmp; 30 fac.clear(); 31 tmp = (int) (sqrt((double) n) + EPS); 32 for (i = 1; i <= tmp; i++) { 33 if (n % i == 0) { 34 fac.push_back(i); 35 if (i == tmp && i * i == n) 36 continue; 37 fac.push_back(n / i); 38 } 39 } 40 } 41 int PowMod(int a, int b, int c) { 42 int res; 43 a %= c; 44 for (res = 1; b; b >>= 1) { 45 if (b & 1) { 46 res *= a; 47 res %= c; 48 } 49 a *= a; 50 a %= c; 51 } 52 return res; 53 } 54 void Prime(int x) { 55 int i, tmp; 56 g.clear(); 57 tmp = (int) (sqrt((double) x) + EPS); 58 for (i = 0; prime[i] <= tmp; i++) { 59 if (x % prime[i] == 0) { 60 g.push_back(prime[i]); 61 while (x % prime[i] == 0) 62 x /= prime[i]; 63 } 64 } 65 if (x > 1) 66 g.push_back(x); 67 } 68 int Mul(int x, int &k) { 69 int i, ans = 1; 70 for (i = k = 0; x; x >>= 1, i++) { 71 if (x & 1) { 72 ans *= g[i]; 73 k++; 74 } 75 } 76 return ans; 77 } 78 int Count(int x) { 79 int i, j, t, tmp, ans; 80 Prime(x); 81 ans = 0; 82 t = (int) g.size(); 83 for (i = 1; i < (1 << t); i++) { 84 tmp = Mul(i, j); 85 if (j & 1) 86 ans += x / tmp; 87 else 88 ans -= x / tmp; 89 } 90 return (x - ans) % P; 91 } 92 int main() { 93 int c; 94 int n, ans, i; 95 Init(); 96 scanf("%d", &c); 97 while (c--) { 98 scanf("%d%d", &n, &P); 99 Factor(n); 100 ans = 0; 101 for (i = 0; i < (int) fac.size(); i++) { 102 ans += PowMod(n, fac[i] - 1, P) * Count(n / fac[i]); 103 ans %= P; 104 } 105 printf("%d\n", ans); 106 } 107 return 0; 108 }