赛题 #D: P5176 公约数

这道题貌似就是让你求一个式子:

\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{k=1}^{p}gcd(i*j,i*k,j*k)*gcd(i,j,k)*(\frac{gcd(i,j)}{gcd(i,k)*gcd(j,k)}+\frac{gcd(i,k)}{gcd(i,j)*gcd(j,k)}+\frac{gcd(j,k)}{gcd(i,j)*gcd(i,k)})

一开始看到这个式子有些怕怕的,然后推了一下发现并不难

首先我们发现一个事实:

gcd(i*j,i*k,j*k)=\frac{gcd(i,j)*gcd(i,k)*gcd(j,k)}{gcd(i,j,k)}

冷静思考一下对于每个质因子出现的个数:左边那个式子就是该质因子在i,j,k中出现的(最小次数+次小次数)就是最终次数

而右边那个式子的分母就是该质因子出现的最小次数,分子是(2×最小次数+次小次数)减一下发现就是(最小次数+次小次数)

所以式子就变为

\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{k=1}^{p}gcd(i,j)^2+gcd(i,k)^2+gcd(i,k)^2

然后我们就可以把他们独立开来了

p*\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)^2+n*\sum_{i=1}^{m}\sum_{j=1}^{p}gcd(i,j)^2+m*\sum_{i=1}^{n}\sum_{j=1}^{p}gcd(i,j)^2

然后我们直接莫比乌斯反演一下就行了

S(n)=\sum_{i|n}\mu(i)*(\frac{n}{i})^2

那么

\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)^2=\sum_{i=1}^{min(n,m)}S(i)*\left \lfloor \frac{n}{i} \right \rfloor*\left \lfloor \frac{m}{i} \right \rfloor

因为S(n)是可以预处理出来的,所以直接分块一下就行了

预处理:

设n的最小质因子为p

1)如果p在n中的次数大于1,显然S(n)=S(\frac{n}{p})*p^2

2)如果p在n中的次数等于1,我们思考一下由于这个新的质因子所产生新的会产生贡献的\mu,不考虑新产生的\mu,那么这就是

S(\frac{n}{p})*p^2,在考虑必须包含这个质数p的\mu,我们发现他就是-S(\frac{n}{p}),因为这个新质因子的加入意味着原来他去掉的这个新质因子的\mu全部取反,这时候由于必须包含这个新质因子,故他不会产生^2贡献,所以得证

所以S(n)=S(\frac{n}{p})*(p^2-1)

这个东西在欧筛的同时就可以搞定了

#include
#define ll long long
using namespace std;
const ll mod=1e9+7;
const int N=2e7;
int T;
int prime[10000000];
ll ans[N+10],mu[N+10];
bool p[N+10];
int len;
ll n,m,w;
 templatevoid read(T &x)
 {
    x=0;int f=0;char ch=getchar();
     while(ch<'0'||ch>'9')  {f|=(ch=='-');ch=getchar();}
     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
     x=f?-x:x;
    return;
 }
ll sqr(ll x)
{
	return (x*x)%mod;
}
void init()
{
	mu[1]=1;
	ans[1]=1;
	for (int i=2;i<=N;i++)
	{
         if (!p[i]) {
         	prime[++len]=i; ans[i]=(sqr(i)+mod-1)%mod; mu[i]=-1;
         }
         for (int j=1;j<=len&&prime[j]*i<=N;j++) {
         	p[prime[j]*i]=1;
         	if (i%prime[j]==0) {
         		mu[i*prime[j]]=0; ans[i*prime[j]]=(ans[i]*sqr(prime[j]))%mod; break;
         	}
         	else mu[i*prime[j]]=-mu[i],ans[i*prime[j]]=(ans[i]*((sqr(prime[j])-1+mod)%mod)%mod);
         }
	}
	for (int i=1;i<=N;i++) ans[i]=(ans[i-1]+ans[i])%mod;
}
ll solve(ll x,ll y){
	ll sum=0;
	int last;
	for (int i=1;i<=x&&i<=y;i=last+1)
	{
		last=min(x/(x/i),y/(y/i));
		sum=(sum+(x/(ll)i)*(y/(ll)i)%mod*((ans[last]-ans[i-1]+mod)%mod)%mod)%mod;
	}
	return sum;
}
int main()
{
	scanf("%d",&T);
	init();
	while (T--) {
		read(n); read(m); read(w);
		printf("%lld\n",(solve(n,m)*w%mod+solve(n,w)*m%mod+solve(m,w)*n%mod)%mod);
	}
}

 

你可能感兴趣的:(赛题 #D: P5176 公约数)