[BZOJ2820]YY的GCD

Description:

\(\sum_{i=1}^{n} \sum_{j=1}^{m} gcd(i,j)==p\ _{p \in Prime}\)

Hint:

\(数据组数<=1e4,n,m<=1e7\)

Solution:

$ \sum_{p \in Prime} \sum_{i=1}^{n} \sum_{j=1}^{m} gcd(i,j)==p $

$ \sum_{p \in Prime} \sum_{i=1}^{ \lfloor \frac {n} {p} \rfloor } \sum_{j=1}^{ \lfloor \frac {m} {p} \rfloor } gcd(i,j)==1 $

$ \sum_{p \in Prime} \sum_{i=1}^{ \lfloor \frac {n} {p} \rfloor } \sum_{j=1}^{ \lfloor \frac {m} {p} \rfloor } \sum_{d|gcd(i,j)} \mu(d) $

$ \sum_{p \in Prime} \sum_{i=1}^{ \lfloor \frac {n} {p} \rfloor } \sum_{j=1}^{ \lfloor \frac {m} {p} \rfloor } \sum_{d|gcd(i,j)} \mu(d) $

$ \sum_{p \in Prime} \sum_{i=1}^{ \lfloor \frac {n} {p} \rfloor } \sum_{j=1}^{ \lfloor \frac {m} {p} \rfloor } [\ d\ |\ i\ ][\ d\ |\ \ j] \mu(d) $

$ \sum_{p \in Prime} \sum_{d}^{\lfloor \frac {min(n,m)} {p} \rfloor} \mu (d) \sum_{i=1}^{ \lfloor \frac {n} {p} \rfloor } \sum_{j=1}^{ \lfloor \frac {m} {p} \rfloor } $

$ \sum_{p \in Prime} \sum_{d}^{\lfloor \frac {min(n,m)} {p} \rfloor} \mu (d) \lfloor \frac {n} {dp} \rfloor \lfloor \frac {m} {dp} \rfloor $

换元得

$ \sum_{p \in Prime} \sum_{T=1}^{min(n,m)} \mu (\frac{T}{p}) \lfloor \frac {n} {T} \rfloor \lfloor \frac {m} {T} \rfloor $

$ \sum_{T=1}^{min(n,m)} \lfloor \frac {n} {T} \rfloor \lfloor \frac {m} {T} \rfloor \sum_{p \in Prime} \mu(\frac{T}{p}) $

将前缀和特殊处理一下,直接枚举T即可


#include<bits/stdc++.h>
using namespace std;
const int mxn=1e7+5;
int n,m,T,tot,mu[mxn],vis[mxn],p[mxn],f[mxn];
long long sum[mxn];

void sieve(int lim)
{
	mu[1]=1;
	for(int i=2;i<=lim;++i) {
		if(!vis[i]) mu[i]=-1,p[++tot]=i;
		for(int j=1;j<=tot;++j) {
			if(p[j]*i>lim) break;
			vis[p[j]*i]=1;
			if(i%p[j]==0) {
				mu[i*p[j]]=0;
				break;
			}
			mu[p[j]*i]=-mu[i];
		}
	}
	for(int i=1;i<=lim;++i) {
		for(int j=1;j<=tot;++j) {
			if(p[j]*i>lim) break;
			else f[p[j]*i]+=mu[i]; //特殊处理
		}
	}
	for(int i=1;i<=lim;++i) sum[i]=sum[i-1]+f[i];
}

int main()
{
	scanf("%d",&T);
	sieve(10000000);
	while(T--) {
		long long ans=0;
		scanf("%d%d",&n,&m); if(n>m) swap(n,m);
		for(int l=1,r;l<=n;l=r+1) {
			r=min(n/(n/l),m/(m/l));
			ans+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2019-02-13 14:03  cloud_9  阅读(81)  评论(0编辑  收藏  举报