hdu5072 容斥原理

统计一下每个约数在数列中是多少数的约数,然后就是容斥原理搞一下。

对任意一个数,求其三个数互质或三个数全不互质的数量,就是总数减去三个数两个互质剩余至少一对不互质的个数。对于一个数a,数列中的数要么与其互质,要么不互质,假设互质的数的个数为n1,那么不互质的数的个数就是n-n1-1,然后取三个数就是取一个与a互质的和一个与a不互质的数,取法共有n1*(n-n1-1),这样取的话会重复一遍,可以假设以a为轴取的三个数为a,b,c,其中a和b互质,a和c不互质,如果b和c也互质,那么以c为轴取的c,b,a重复了一遍,如果b,c不互质,那么b,a,c重复了一遍,所以最后算出的结果总数要除2,便是三个数两个互质且第至少有一对不互质的取法个数,然后再用总数减一下就得到了结果。

附代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>

using namespace std;

typedef long long ll;

ll v[100010];
int have[100010];
ll ss[100010];
ll maxn;
ll n;

void build()
{
    memset(have,0,sizeof(have));
    for (int i=1;i<=n;i++)
        have[v[i]]=1;
    for (int i=2;i<=maxn;i++)
        for (int t=i;t<=maxn;t+=i)
            if (have[t])
                ss[i]++;
    return ;
}

ll solve(int k)
{
    vector <int> p;
    for (int i=2;i*i<=k;i++)
    {
        if (k%i==0)
            p.push_back(i);
        while (k%i==0)
            k/=i;
    }
    if (k>1)
        p.push_back(k);
    int mm=(1<<p.size())-1;
    ll ans=0;
    for (int i=1;i<=mm;i++)
    {
        ll pp=1;
        ll cc=0;
        for (int t=0;t<p.size();t++)
        {
            int x=(1<<t);
            int temp=i;
            if (temp&x)
            {
                pp*=p[t];
                cc++;
            }
            temp>>=1;
        }
        if (cc&1)
            ans+=ss[pp]-1;
        else
            ans-=ss[pp]-1;
    }
    return (n-ans-1)*ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        maxn=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&v[i]);
            if (v[i]>maxn)
                maxn=v[i];
        }
        memset(ss,0,sizeof(ss));
        build();
        ll ans=0;
        for (int i=1;i<=n;i++)
            ans+=solve(v[i]);
        ll a1=(n*(n-1)*(n-2))/6;
        ans=a1-ans/2;
        printf("%I64d\n",ans);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值