hdu5072(鞍山regional problem C):容斥,同色三角形模型

现场过的第四多的题。。当时没什么想法,回来学了下容斥,又听学长讲了一讲,终于把它过了

题目大意:
给定n个数,求全部互质或者全部不互质的三元组的个数

先说一下同色三角形模型

n个点 每两个点连一条边(可以为红色或者黑色),求形成的三条边颜色相同的三角形的个数

反面考虑这个问题,只需要c(n,3)减去不同色的三角形个数即可

对于每一个点,所形成的不同色三角形即为 红色边的数量*黑色边的数量,所以可以O(n)地算出不同色三角形的个数(注意总数要除以2)

然后用c(n,3)减一下即可

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

那如何求 互质的个数和不互质的个数呢

我们可以预处理范围内每个数的倍数的数量,然后对每个数分解质因子,最后容斥一下即可

代码:

#include <iostream>
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<ctype.h>
using namespace std;
#define MAXN 1000
long long n;
int a[100010];
int prime[100010];
int num[100010];
int isnotprime[100010];
int num_prime=0;
int fac[100010][10];
int np[100010];
long long gcd(long long a,long long b)
{
    return b?gcd(b,a%b):a;
}
long long lcm(long long a,long long b)
{
    return a/gcd(a,b)*b;
}
void setprime()
{
    for(int i = 2 ; i < MAXN ; i ++)
    {
        if(!isnotprime[i])
             prime[num_prime ++]=i;
        for(int j=0;j<num_prime&&i*prime[j]<MAXN;j++)
        {
            isnotprime[i * prime[j]] = 1;
            if(!(i%prime[j] ) )
                break;
        }
    }
    return ;
}
void setfac(int x,int pos)
{
    np[pos]=0;
    for(int i=0;i<num_prime;i++)
    {
        if(!(x%prime[i]))
        {
            fac[pos][np[pos]++]=prime[i];
        }
        while(!(x%prime[i]))
        {
            x/=prime[i];
        }
    }
    if(x>1)
    {
        fac[pos][np[pos]++]=x;
    }
}
long long iae(int pos)
{
    long long res=0;
    for(int i=1;i<(1<<np[pos]);i++)
    {
        long long mut=1,tmp=0;
        for(int j=0;j<np[pos];j++)
        {
            if(i&(1<<j))
            {
                mut*=fac[pos][j];
                tmp++;
            }
        }
        if(tmp&1)
        {
            res+=num[mut]-1;
        }
        else
        {
            res-=num[mut]-1;
        }
    }
    return res;
}
void setnum()
{
    for(int i=2;i<=100000;i++)
    {
        for(int j=i+i;j<=100000;j+=i)
            num[i]+=num[j];
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
        //freopen("in.txt","r",stdin);
    #endif
    int T;
    setprime();
    scanf("%d",&T);
    while(T--)
    {
        memset(num,0,sizeof(num));
        scanf("%I64d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",a+i);
            num[a[i]]++;
            setfac(a[i],i);
        }
        setnum();
        long long ans=0;
        for(int i=0;i<n;i++)
        {
            int tmp=iae(i);
            ans+=(n-1-tmp)*tmp;
        }
        ans=n*(n-1)*(n-2)/6-ans/2;
        printf("%I64d\n",ans);
    }
    return 0;
}

 

posted @ 2014-10-23 18:18  PlasticSpirit  阅读(815)  评论(0编辑  收藏  举报