zoukankan      html  css  js  c++  java
  • poj 3904

    题意:给出n个数,问有多少组(a,b,c,d)公约数为1。

    题解:有两种思路,一个是mobius反演,一种是容斥。

    先介绍一下容斥的思路:我们考虑该问题的逆问题,求多少组数的gcd>=2,那么集合gcd为质数的交集就是我们要答案咯。枚举出每个素数乘积的因子数字,然后容斥筛一遍就可以了

    (2017.9.2 这里补充一下,关于为什么用包含某个素因子个数的并集可以表示所有解。有点类似数筛的思想。比如,我们计算包含2这个因子的个数的时候,是不是把包含2,4,6,8等因子的结果一并算进去了,3的时候也是一样,把,3,6,9。这个过程和埃氏筛法的思想类似,一定可以包含所有的情况,然后其并集就是我们要的答案)

    #include<stdio.h>  
    #include<string.h>  
    using namespace std;  
    #define LL long long  
    #define maxn 10005  
      
    LL node[maxn],num[maxn],vist[maxn],prime[maxn];  
    void Init()  
    {  
        LL i;  
        for(i=4;i<maxn;i++)  
            node[i]=i*(i-1)*(i-2)*(i-3)/24;  
    }  
      
    void make_count(int m)  
    {  
        int i,j,tmp,flag,cnt=0;  
        for(i=2;i*i<=m;i++)  
            if(m&&m%i==0)  
            {  
                prime[cnt++]=i;  
                while(m&&m%i==0)  
                    m/=i;  
            }     
        if(m>1)  
            prime[cnt++]=m;  
        for(i=1;i<(1<<cnt);i++)  
        {  
            tmp=1,flag=0;  
            for(j=0;j<cnt;j++)  
                if(i&(1<<j))  
                    flag++,tmp*=prime[j];  
            num[tmp]++;  //统计当前因子出现的次数  
            vist[tmp]=flag; //记录当前因子是由多少个素因子组成,奇加偶减  
        }  
    }  
      
    int main()  
    {  
        Init();  
        int n,i,x;  
        while(~scanf("%d",&n))  
        {  
            memset(num,0,sizeof(num));  
            memset(vist,0,sizeof(vist));  
            for(i=0;i<n;i++)  
            {  
                scanf("%d",&x);  
                make_count(x);  
            }  
            LL ans=0;  
            for(i=1;i<maxn;i++)  
                if(num[i])  
                {  
                    if(vist[i]&1)  
                        ans+=node[num[i]];  
                    else  
                        ans-=node[num[i]];  
                }  
            printf("%I64d
    ",node[n]-ans);            
        }  
        return 0;  
    }  
    容斥

    mobius:常见的为求gcd()==k 或者gcd为质数的情况

    我们令
    f(x)=四个数的gcd是x的情况数 ;

    F(x)=四个数的gcd是x的倍数的情况;

    这里要求的n为1。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    ll num[10001];
    ll mu[10001];
    ll c[10001];
    ll vis[10001];
    ll prime[10001];
    void init()
    {
        for(ll i=1;i<=10000;i++)
        {
            c[i]=i*(i-1)*(i-2)*(i-3)/24;
        }
        memset(mu,0,sizeof(mu));
        memset(vis,0,sizeof(vis));
        memset(prime,0,sizeof(prime));
        int ret=0;
        mu[1]=1;
        for(int i=2;i<=10000;i++)
        {
            if(!vis[i])
            {
                mu[i]=-1;
                prime[ret++]=i;
            }
            for(int j=0;j<ret &&i*prime[j]<=10000;j++)
            {
                ll temp=i*prime[j];
                vis[temp]=1;
                if(i%prime[j])
                {
                    mu[temp]=-mu[i];
                }
                else break;
            }
        }
    }
    void get(ll x)
    {
        for(ll i=1;i*i<=x;i++)
        {
            if(x%i==0)
            {
                num[i]++;
                if(i*i!=x) num[x/i]++;// attention//
            }
        }
    }
    int main()
    {
        int n;
        init();//
        while(~scanf("%d",&n))
        {
            ll x;
            memset(num,0,sizeof(num));
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&x);
                get(x);
            }
            ll ans=0;
            for(int i=1;i<=10000;i++)
            {
                if(mu[i]==0 || num[i]<4) continue;
                ans+=mu[i]*c[num[i]];
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    WebService
    JavaMail
    ssh框架整合
    CSS3初步
    SpringMVC 文件上传及下载
    Java多线程
    SpringMVC 数据校验
    初始化参数绑定——日期格式
    SpringMVC入门
    Quartz
  • 原文地址:https://www.cnblogs.com/z1141000271/p/7325429.html
Copyright © 2011-2022 走看看