poj 3904(莫比乌斯反演)

来源:互联网 发布:福建医科大学网络教育 编辑:程序博客网 时间:2024/06/07 14:48

POJ 3904 

题意:

从n个数中选择4个数使他们的GCD = 1,求总共有多少种方法

Sample Input

42 3 4 5 42 4 6 8 72 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非常感谢


/*POJ3904Tc_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_());    }}



0 0