题意:给定n个数,从n个数找出四个数,使这四个数的最大公约数为1,找出有多少对这样的组合。
找最大公约数不是1的有多少对。
题解:四个数的公约数为1,并不代表四个数两两互质。比如(2,3,4,5)公约数为1,但是
2和4并不互质。从反面考虑,先求出四个数公约数不为1的情况个数,用总的方案个数
减去四个数公约数不为1的情况个数就是所求。
求四个数公约数不为1的情况个数,需要将N个数每个数质因数分解,纪录下所有不同
的素因子所能组成的因子(就是4个数的公约数),并统计构成每种因子的素因子个数,
和因子总数。然后再计算组合数。比如说因子2的个数为a,则四个数公约数为2的个数
为C(a,4),因子3的个数为b,则四个数公约数为3的个数为C(b,4),因子6(2*3)的个
数为c,则四个数公约数的个数为C(c,4)。
但是公约数为2的情况中或者公约数为3的情况中可能包括公约数为6的情况,相当于几
个集合求并集,这就需要容斥定理来做。
容斥原理应用,以2为因子的数有a个,3为因子 的数有b个,6为因子的数有c个,
n个数不互质的四元组个数为C(4,a)+C(4,b)-C(4,c) (含奇数个素因子的加,偶数个素因子的减),
下面就是统计出2,3,5这些因子的倍数的个数,对C(4,a)容斥!
代码:弄清思路以后就很好做了,一环扣一环,用二进制进行枚举,很棒!
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <math.h> #include <stdlib.h> using namespace std; typedef long long ll; ll c(ll n) { return n*(n-1)*(n-2)*(n-3)/24; } ll f[10010],cnt,ccount[10010],num[10010]; void div(ll n) { cnt=0; for(int i=2;i<=sqrt(n);i++) { if(n%i==0) f[cnt++]=i; while(n%i==0) n/=i; } if(n!=1) f[cnt++]=n; } void solve(ll n) { div(n); for(int i=1;i<(1<<cnt);i++) { ll tmp=1,flag=0; for(int j=0;j<cnt;j++) { if(i&(1<<j)) { flag++; tmp*=f[j]; if(tmp>n) break; } } ccount[tmp]++; //count是关键字 不能用 num[tmp]=flag; } } int main() { ll n,m; while(scanf("%lld",&n)!=EOF) { memset(ccount,0,sizeof(ccount)); for(int i=0;i<n;i++) { scanf("%lld",&m); solve(m); } ll ans=c(n); for(int i=0;i<=10000;i++) { if(ccount[i]) { if(num[i]&1) ans-=c(ccount[i]); else ans+=c(ccount[i]); } } printf("%lld\n",ans); } return 0; }
时间: 2024-10-12 09:16:02