Hdu 5072 Coprime(容斥+同色三角形)

原题链接

题意
选出三个数,要求两两互质或是两两不互质。求有多少组这样的三个数。

分析

同色三角形
n个点 每两个点连一条边(可以为红色或者黑色),求形成的三条边颜色相同的三角形的个数
反面考虑这个问题,只需要c(n,3)减去不同色的三角形个数即可
对于每一个点,所形成的不同色三角形即为 红色边的数量*黑色边的数量,所以可以O(n)地算出不同色三角形的个数(注意总数要除以2)
然后用c(n,3)减一下即可

对于这个题,如果把互质看作红色边,不互质看作黑色边,就可以转化为同色三角形问题了

那如何求 互质的个数和不互质的个数呢?
[可以参考一下这里]利用容斥原理求出每个数的不互质个数m,那么互质个数则为n-m-1。最终答案则为C(n,3)-m*(n-m+1)/2.
预处理每个数的质因子,计算出每种质因子搭配的个数(表明n个数中有多少个为其倍数)num[].

其他看代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
using namespace std;
#define eps 1e-12
#define inff 0x3fffffff
#define nn 110000
typedef __int64 LL;
int n;
int a[nn];
int num[nn];
vector<int>p[nn];
bool use[nn];
void init()
{
    memset(use,false,sizeof(use));
    for(int i=2;i<=100000;i++)//分解质因子
    {
        if(!use[i])
        {
            for(int j=i;j<=100000;j+=i)
            {
                p[j].push_back(i);
                use[j]=true;
            }
        }
    }
}
int main()
{
    int t,i,j,k;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        memset(num,0,sizeof(num));
        int lv;
        int ix;
        for(i=1;i<=n;i++)//状压
        {
            if(a[i]==1)
                continue;
            lv=p[a[i]].size();
            for(j=1;j<(1<<lv);j++)
            {
                ix=1;
                for(k=0;k<lv;k++)
                {
                    if(((1<<k)&j))
                    {
                        ix*=p[a[i]][k];
                    }
                }
                num[ix]++;//表示n个数中为ix的倍数的个数
            }
        }
        int fc;
        LL tem;
        LL ans=0;
        LL m=n;
        for(i=1;i<=n;i++)
        {
            if(a[i]==1)
                continue;
            lv=p[a[i]].size();
            tem=0;
            for(j=1;j<(1<<lv);j++)
            {
                ix=1;
                fc=0;
                for(k=0;k<lv;k++)
                {
                    if(((1<<k)&j))
                    {
                        ix*=p[a[i]][k];
                        fc++;
                    }
                }
                if(fc&1)
                {
                    tem+=num[ix];
                }
                else
                    tem-=num[ix];
            }
            //tem-1才是与其不互质的个数,意思为减去自身
            ans+=(tem-1)*(m-tem);
        }
        ans/=2;
        ans=m*(m-1)*(m-2)/6-ans;
        printf("%I64d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/7261066.html