poj 3904(莫比乌斯反演)
题意:
从n个数中选择4个数使他们的GCD = 1,求总共有多少种方法
Sample Input
4 2 3 4 5 4 2 4 6 8 7 2 3 4 5 7 6 8
Sample Output
1 0 34
思路:先求出选择四个数所有的情况,C(4,n) = n * (n-1) * (n-2) * (n-3),然后减去GCD为2,GCD为3......;在这过程中我们会把GCD = 6减去两次,所以需要加上。刚好满足莫比乌斯函数
函数:合数为0 ,质数数目为奇 -1,质数数目为偶 1
先筛出mu函数,然后求即可
Tc_To_Top非常感谢
/* POJ3904 Tc_To_Top:http://blog.csdn.net/tc_to_top/article/details/49130111 非常感谢,让我对莫比乌斯有了进一步了解- -/*毕竟弱 以前对这个求GCD一直很模糊, C(n,k) - C(gcd只含奇数个质数的个数,k) + C(gcd只含偶数个质数的个数,k),前面的符号就是莫比乌斯函数 先求出所有可能的情况,然后容斥原理需要减去以及加上一些数,而这就极好的利用了莫比乌斯原理。 不是有一种求1≤x≤a,1≤y≤b中一共有多少对互质的数 for(int i = 1;i <= n;i++) ans += mu[i]*(n/i)*(n/i); 感觉就是上面原理的压缩版,i等于一时求出所有情况,然后减去GCD=2,....加上GCD=6... (#‵′)靠,感觉自己好坑 - -! 居然纠结半天 */ #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <vector> #include <algorithm> #include <functional> typedef long long ll; using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 1e5; int tot; int is_prime[maxn]; int mu[maxn]; int prime[maxn]; void Moblus() { tot = 0; mu[1] = 1; for(int i = 2; i < maxn; i++) { if(!is_prime[i]) { prime[tot++] = i; mu[i] = -1; } for(int j = 0; j < tot && i*prime[j] < maxn; j++) { is_prime[i*prime[j]] = 1; if(i % prime[j]) { mu[i*prime[j]] = -mu[i]; } else { mu[i*prime[j]] = 0; break; } } } } int tmax; int num[maxn],cnt[maxn]; ll get_() { for(int i = 1; i <= tmax; i++) { for(int j = i; j <= tmax; j+=i) { cnt[i] += num[j]; //计算GCD为i的集合中的个数 } } ll ans = 0; for(int i = 1; i <= tmax; i++) { int tt = cnt[i]; if(tt >= 4) ans += (ll)mu[i]*tt*(tt-1)*(tt-2)*(tt-3)/24; } return ans; } int main() { int n; Moblus(); while(scanf("%d",&n)!=EOF) { memset(num,0,sizeof(num)); memset(cnt,0,sizeof(cnt)); for(int i = 0; i < n; i++) { int tt; scanf("%d",&tt); num[tt] ++; tmax = max(tmax,tt); } if(n < 4) printf("0\n"); else printf("%lld\n",get_()); } }