• poj 3904(莫比乌斯反演)


    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
    ");
            else
                printf("%lld
    ",get_());
        }
    }
    

      


    
    
  • 相关阅读:
    随时积累随手记(持续更新...)
    Zookeeper集群搭建
    Dubbo——基于Zookeeper服务框架搭建及案例演示
    nginx配置浅析
    阿里面试回来,想和Java程序员谈一谈
    博客收藏列表
    启示录:打造用户喜爱的产品
    js深拷贝和浅拷贝
    MyBatis 总结记录
    ActiveMQ初体验
  • 原文地址:https://www.cnblogs.com/Przz/p/5409694.html
Copyright © 2020-2023  润新知