SP4191 MSKYCODE

洛咕

题意:给你n个数,现在让你求出有多少个四元组,满足这四个数的最大公约数等于1,n<=10000,每个数<=10000,多组询问,对于每个询问回答有多少个四元组满足条件.

分析:设(f(d))为选出(4)个数(gcd)(d)的个数,设(F(d))表示为选出(4)个数公约数为(d)的方案数,所以由莫比乌斯反演,则有(f(d)=sum_{d|x}F(x)μ(frac xd))

(ans=f(1)=sum_{x=1}^{10000}F(x)μ(x))

即对于一个数(i(1<=i<=10000)),设有(sum[i])个数是它的倍数,然后求(C_{sum[i]}^4*μ(i))累加进(ans)即可.

恶心的(long) (long......)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read(){
   int s=0,w=1;char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
   return s*w;
}
const int N=10005;
int n,mu[N],v[N],prime[N],sum[N];
inline void get_mu(){
    int m=0;mu[1]=1;
    for(int i=2;i<=10000;i++){
		if(!v[i]){
	    	v[i]=i;
	    	prime[++m]=i;
	    	mu[i]=-1;
		}
		for(int j=1;j<=m;j++){
	    	if(prime[j]*i>10000)break;
	    	v[prime[j]*i]=prime[j];
	    	if(i%prime[j]==0)break;
	    	else mu[i*prime[j]]=-mu[i];
		}
    }
}
inline LL C(int n){return 1ll*n*(n-1)*(n-2)*(n-3)/24;}
int main(){
    get_mu();
    while(~(scanf("%d",&n))){
		LL ans=0;for(int i=1;i<=10000;i++)sum[i]=0;
		for(int i=1;i<=n;i++){
	    	int j,m=read();
	    	for(j=1;j*j<m;j++)
         		if(m%j==0)sum[j]++,sum[m/j]++;
	    	if(j*j==m)sum[j]++;
		}
		for(int i=1;i<=10000;i++)
        	ans=ans+1ll*mu[i]*C(sum[i]);
		printf("%lld
",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/10864510.html