1 5 1 3 9 10 2
4
求从n个数字中选出a,b,c三个数字,要么两两互质,要么两两不互质,求组合数。
那么解 = 所有组合数 - 互质和不互质同时存在的组合数
那么求出与a[i]不互质的数的个数,就能算出与a[i]互质的数的个数
求法:统计每个数字能做为那么数字的因素
对于一个数字,分解质因数,然后用容斥原理算出与这个数不互质的数的个数。
那么对于a[i],选择一个互质的数的情况*选择一个不互质的数的情况 = 得到的是不满足条件的且包含a[i]的情况。
由于对每个数字都进行处理,最后的结果是不满足情况的数量*2
#include<iostream> #include<cstdio> #include<vector> #include<cstring> using namespace std; #define ll long long #define maxn 100007 int check[maxn]; vector<int> prin[maxn]; int num[maxn]; void init(){ memset(check,0,sizeof(check)); for(int i = 2;i < maxn; i++){ if(check[i] == 0) { for(int j = i;j < maxn; j+=i){ check[j] = 1; prin[j].push_back(i); } } } } int main(){ init(); int n,t,u,s; scanf("%d",&t); while(t--){ scanf("%d",&n); memset(check,0,sizeof(check)); memset(num,0,sizeof(num)); for(int i = 0;i < n; i++){ scanf("%d",&check[i]); num[check[i]]++; } for(int i = 1;i < maxn; i++) for(int j = i+i; j < maxn; j+= i) num[i] += num[j]; ll res = 0,ans = 0; for(int i = 0;i < n; i++){ u = check[i]; res = 0,s = prin[u].size(); for(int j = 1;j < (1<<s); j++){ int v = 1,f = 0; for(int k = 0;k < s; k++){ if((1<<k)&j){ f++; v *= prin[u][k]; } } if(f&1) res += num[v]-1; else res -= num[v]-1; } if(res) ans += res*(n-res-1); } ans = 1ll*n*(n-1)*(n-2)/6-ans/2; printf("%I64d\n",ans); } return 0; }