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; }