HDU 4048 Zhuge Liang's Stone Sentinel Maze [组合数学+Burnside]
2012-10-31 21:05
471 查看
给出M个不同的数,每个数有无穷多个。从中选N个组成环,问最大公约数为1的方案有多少种。
上一题是这题的基础,不同的是每个数可以选多个,tot[i]表示m个数中i的倍数有多少个,那么用构成长度为l最大公约数为i的倍数的方案有tot[i]^l种,之后再用容斥求一下最大公约数为1的方案即可。
另外要考虑循环同构,套一个Burnside就行了,坑的就是N是10007倍数的情况,WA了N次。。要将MOD*n。。
上一题是这题的基础,不同的是每个数可以选多个,tot[i]表示m个数中i的倍数有多少个,那么用构成长度为l最大公约数为i的倍数的方案有tot[i]^l种,之后再用容斥求一下最大公约数为1的方案即可。
另外要考虑循环同构,套一个Burnside就行了,坑的就是N是10007倍数的情况,WA了N次。。要将MOD*n。。
#include <stdio.h> #include <string.h> #include <algorithm> #define MAXN 20010 int MOD; using namespace std; typedef long long LL; int cas, n, m, tx; int pri[MAXN], notp[MAXN], flag[MAXN], prs; int tot[MAXN], maxm; int fac[MAXN][305], facs[MAXN], phi[MAXN * 10]; void init(){ for (int i = 2; i < MAXN; i++) if (!notp[i]) { flag[i] = 1; for (int j = i*2; j < MAXN; j += i) { if (!notp[j]) notp[j] = flag[j] = 1; else if (flag[j]) flag[j]++; if (j%(i*i) == 0) flag[j] = 0; } } for (int i = 2; i < MAXN; i++) if (!notp[i]) pri[prs++] = i; for (int i = 1; i < MAXN; i++) for (int j = 1; j * j <= i; j++) if (i % j == 0) { fac[i][facs[i]++] = j; if (j * j != i)fac[i][facs[i]++] = i/j; } const int maxn = 100000; for (int i = 1; i <= maxn; i ++) phi[i] = i; for (int i = 2; i <= maxn; i ++) if(phi[i] == i) { for(int j = i; j <= maxn; j += i) phi[j] = phi[j] / i * (i - 1); } } int powmod(int x, int d){ int ans = 1, tmp = x; for (; d; d >>= 1, tmp = (LL)tmp * tmp % MOD) if (d&1) ans = (LL)ans * tmp % MOD; return ans; } int cal(int l){ int ans = powmod(tot[1], l); for (int i = 2; i <= maxm; i++) { if (flag[i] == 0) continue; if (flag[i] & 1) ans = (ans - powmod(tot[i], l)) % MOD; else ans = (ans + powmod(tot[i], l)) % MOD; } return (ans % MOD + MOD) % MOD; } void solve(){ int ans = 0; for(int i = 1; i * i <= n; i ++) if(n % i == 0) { ans = (ans + (LL)cal(i) * phi[n / i]) % MOD; if(i * i != n) ans = (ans + (LL)cal(n / i) * phi[i]) % MOD; } printf("%d\n", (ans + MOD) % MOD / n); } int main(){ //freopen("test.in","r",stdin); init(); scanf("%d", &cas); while (cas--) { scanf("%d%d", &m, &n); MOD = 10007 * n; memset(tot, 0, sizeof tot); maxm = 0; for (int i = 1; i <= m; i++) { scanf("%d", &tx); maxm = max(tx, maxm); for (int j = 0; j < facs[tx]; j++) tot[fac[tx][j]]++; } solve(); } return 0; }
相关文章推荐
- 组合数学第二发 错排问题 hdu 2049 + hdu 2068
- HDU 5894 hannnnah_j’s Biological Test (组合数学 + 快速幂 + 乘法逆元)
- hdu 4810 Wall Painting (组合数学+二进制)
- hdu 2965组合数学题
- hdu 6143 组合数学+dp
- hdu 4810 Wall Painting(组合数学)
- HDU 4869 Turn the pokers【组合数学】
- HDU 4349 Xiao Ming's Hope 组合数学
- HDU 4248【组合数学 + DP】
- HDU 3625 Examining the Rooms (第一类斯特灵数,组合数学)
- hdu2049(组合数学)
- HDU 5459 Jesus Is Here (递推,组合数学)
- hdu 4810 Wall Painting(组合数学)
- 数学 ( 排列组合 )——HDU 5194
- HDU 3240 Counting Binary Trees [卡特兰数] 【数论+组合数学】
- HDU 4372 Count the Buildings 组合数学
- hdu 6036 NTT取模(板子)+组合数学
- hdu 3944 DP? 组合数学与数论的结合
- HDU 5194 DZY Loves Balls(数学组合or各种乱搞)
- Integer’s Power HDU - 3208 组合数学