Uva Coprime(莫比乌斯反演)
题意:n个数中每次选取三个数,这三个数两两互质或两两不互质,求满足条件的三个数的对数;
思路:http://blog.csdn.net/cool_fires/article/details/8681888(数据范围较小的题)
考虑三个数互质的对数的情况可以分为0对,1对,2对,3对,题目要求0对和3对的情况,可以通过求1对和2对的情况取补;
莫比乌斯反演用于辅助求不大于一个数的与该数互质的数的个数;
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int t,n,m; bool check[100010]; int num[100010],cnt[100010],temp[100010]; int prime[100010],mu[100010],mul[100010]; void moblus(){ memset(check,false,sizeof(check)); mu[1]=1; int tot=0; for(int i=2;i<=100000;i++){ if(!check[i]){ prime[tot++]=i; mu[i]=-1; } for(int j=0;j<tot;j++){ if(i*prime[j]>100000) break; check[i*prime[j]]=true; if(i%prime[j]==0){ mu[i*prime[j]]=0; break; } else{ mu[i*prime[j]]=-mu[i]; } } } } int main(){ int i,j,k; moblus(); scanf("%d",&t); while(t--){ scanf("%d",&n); memset(cnt,0,sizeof(cnt)); memset(mul,0,sizeof(mul)); memset(temp,0,sizeof(temp)); for(i=1;i<=n;i++){ scanf("%d",&num[i]); cnt[num[i]]++; } for(i=1;i<=100000;i++){ for(j=i;j<=100000;j+=i){ mul[i]+=cnt[j]; //i及其倍数的个数 } } for(i=1;i<=100000;i++){ for(j=i;j<=100000;j+=i){ temp[j]+=mu[i]*mul[i]; //temp[j]为与j互质的数的个数 } } long long ans; ans=(long long)n*(n-1)*(n-2)/6; long long res=0; for(i=1;i<=n;i++){ if(num[i]==1) continue; res+=(long long)temp[num[i]]*(long long)(n-1-temp[num[i]]); //不包含自身,所以为n-1 } ans-=res/2; //去掉重复计算的情况 printf("%lld\n",ans); } return 0; }

浙公网安备 33010602011771号