zoukankan      html  css  js  c++  java
  • Coprime HDU

    题目

    给出 (n) 个互不相同的数,求出满足要么 (3) 个数都两两互质,要么都不两两互质的三元组的个数。((3leq n leq 10^5,1leq a_i leq 10^5))
    题目链接:https://vjudge.net/problem/HDU-5072

    分析

    如果直接从正面考虑怎么求解的话,会发现难以处理。这时,需要逆向思维考虑。可以发现,不满足要求的三元组的一定存在其中两个数互质而另两个数不互质。假设:(a,b) 互质,(b,c) 不互质。可以通过枚举 (b) 来求解。假设与 (b) 不互质的数的个数为 (x) ,那么 (b) 对答案的贡献为 (frac{(x-1)(n-x)}{2})。之所以要除 (2) ,是因为如果 (a,c) 互质,那么可以交换 (b,c) 的位置;如果 (a,c) 不互质,那么可以交换 (a,b) 的位置,每个答案都被计算了两遍。

    接下来,问题关键在于如何求出有多少个数与 (b) 不互质。可以先利用埃式筛筛出每个数的倍数的个数(在所给数中),然后,对枚举的每个 (b) 进行质因子分解,得到其各个质因子。利用容斥定理,就可以求出与 (b) 不互质的数的个数。最后,要总的个数:(C(n,3)) 减去即可。

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    int a[N],prime[N],cnt,num[N],p[10];
    bool vis[N],book[N];
    void init()
    {
        int maxn=1e5;
        for(int i=2;i<=maxn;i++)
        {
            if(!vis[i]) prime[++cnt]=i;
            for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++)
            {
                vis[i*prime[j]]=1;
                if(i%prime[j]==0)
                    break;
            }
        }
    }
    void solve()
    {
        int maxn=1e5;
        for(int i=1;i<=maxn;i++)
            num[i]=0;
        for(int i=1;i<=maxn;i++)
        {
            for(int j=i;j<=maxn;j+=i)
                if(book[j]) num[i]++;
        }
    }
    int devide(int x)
    {
        int res=0;
        for(int i=1;prime[i]*prime[i]<=x&&i<=cnt;i++)
        {
            if(x%prime[i]==0)
            {
                p[res++]=prime[i];
                while(x%prime[i]==0)
                    x/=prime[i];
            }
        }
        if(x>1)
            p[res++]=x;
        return res;
    }
    int main()
    {
        int t,n;
        init();
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            for(int i=1;i<=1e5;i++) book[i]=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                book[a[i]]=1;
            }
            solve();
            ll ans=0;
            for(int i=1;i<=n;i++)//枚举b
            {
                int m=devide(a[i]);
                ll res=0;//和b不互质的数的个数
                for(int j=1;j<(1<<m);j++)
                {
                    int cot=0;
                    ll tmp=1;
                    for(int k=0;k<m;k++)
                    {
                        if(j&(1<<k))
                        {
                            tmp*=p[k];
                            cot++;
                        }
                    }
                    if(cot&1) res+=num[tmp];
                    else res-=num[tmp];
                }
                if(m==0) continue;
                ans+=(res-1)*(n-res);
            }//cout<<"ans="<<ans<<endl;
            ans=1LL*n*(n-1)*(n-2)/6-ans/2;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    POJ 2251 Dungeon Master
    POJ1321棋盘问题
    CODE[VS] 1003 电话连线
    CCF-201412-1-门禁系统
    CCF-201412-2-Z字形扫描
    为什么要用补码
    CCF-201409-1-相邻数对
    CCF-201409-2-画图
    CCF-201403-1-相反数
    CCF-201403-2-窗口
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/14413887.html
Copyright © 2011-2022 走看看