首页 > 代码库 > [容斥原理] hdu 5072 Coprime
[容斥原理] hdu 5072 Coprime
题意:
给n个数,求这n个数取3个数构成一个集合, 这三个数两两互质或者两两不互质,为有多少种取法。
思路:
首先这可以转换成一个单色三角形的问题。
就是三个数为三角形的三个顶点,两个顶点如果互质则边为1,不互质边为0
为三条边均为1或者均为0的三角形就多少个。
因为三角形的总数我们是知道的,然后我们取对立面算。
那么其实我们可以枚举顶点,然后求出每个数在这些数中和它互质的有多少个,不互质的有多少个
然后各取一个就是我们要的三角形了。
我们假设互质的有X个,不互质的有Y个
那么以Z为顶点的三角形就有(X*Y)/2
最后三角形的总数就是C(N,3)
相减就是答案了
代码:
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"iostream" #define inf 99999999 #define N 100000 #define ll __int64 using namespace std; int yz[N+20],v[N+20]; int mark[500],mcnt,cc[500]; __int64 n; ll dfs(int kk,int x,int lit) { if(x==lit) { ll tep=1; for(int i=0; i<lit; i++) tep*=cc[i]; return yz[tep]; } ll ans=0; for(int i=kk+1; i<mcnt; i++) { cc[x]=mark[i]; ans+=dfs(i,x+1,lit); } return ans; } ll solve() { ll ans=n*(n-1)*(n-2)/6; ll fuck=0; for(int i=0; i<n; i++) { ll sum=0; int tep=v[i]; mcnt=0; memset(mark,0,sizeof(mark)); for(int j=2; j*j<=tep; j++) { if(tep%j==0) mark[mcnt++]=j; while(tep%j==0) tep/=j; } if(tep>1) mark[mcnt++]=tep; for(int i=1; i<=mcnt; i++) { if(i%2) sum+=dfs(-1,0,i); else sum-=dfs(-1,0,i); } if(sum!=0) fuck+=(sum-1)*(n-sum); } return ans-fuck/2; } int main() { int t; cin>>t; while(t--) { scanf("%I64d",&n); memset(yz,0,sizeof(yz)); for(int i=0; i<n; i++) { scanf("%d",&v[i]); for(int j=1; j*j<=v[i]; j++) { if(v[i]%j==0) { yz[j]++; if(v[i]/j!=j) yz[v[i]/j]++; } } } printf("%I64d\n",solve()); } return 0; }
[容斥原理] hdu 5072 Coprime
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。