洛谷P2257 YY的GCD

自律人切题了我也来水一道。

题目描述

多组数据,给定 \(n,m\),求

\[\sum_{x=1}^{n}\sum_{y=1}^{n}{[(x,y)\in \mathbb{P}]} \]

其中 \(\mathbb P\) 表示质数集。

数据范围:\(n,m\le 10^7\)
时间范围:\(4000\text{ms}\)

Solution

不妨设 \(n\le m\)

\[\begin{aligned} &\sum_{x=1}^n\sum_{y=1}^m{[(x,y)\in \mathbb P]}\\ =&\sum_{p\in \mathbb P}\sum_{x=1}^{\lfloor\frac np\rfloor}\sum_{y=1}^{\lfloor\frac mp\rfloor}[(x,y)=1]\\ =&\sum_{p\in \mathbb P}\sum_{x=1}^{\lfloor\frac np\rfloor}\sum_{y=1}^{\lfloor\frac mp\rfloor}\sum_{k\mid x}\sum_{k\mid y}\mu(k)\\ =&\sum_{p\in \mathbb P}\sum_{k=1}^{\lfloor\frac np\rfloor}\mu(k)\lfloor\frac n{pk}\rfloor\lfloor\frac m{pk}\rfloor\\ =&\sum_{d=1}^{n}\lfloor\frac nd\rfloor\lfloor\frac md\rfloor\sum_{p\mid d\land p\in \mathbb P}\mu(\frac dp) \end{aligned} \]

我们发现 \(\sum\limits_{p\mid d\land p\in \mathbb P}\mu(\frac dp)\) 可以预处理前缀和,再套上数论分块即可解决。

时间复杂度为 \(O(n+T\sqrt n)\)

Code

#include<cstdio>
using namespace std;
const int maxn=10000010;
template<class T>inline T Min(const T &a,const T &b){return a<b?a:b;}
int pri[maxn],tot,miu[maxn];
bool vis[maxn];
long long sum[maxn];
inline void Init(){
	miu[1]=1;
	for(int i=2;i<maxn;++i){
		if(!vis[i])pri[++tot]=i,miu[i]=-1;
		for(int j=1;i*pri[j]<maxn;++j){
			vis[i*pri[j]]=1;
			if(i%pri[j])miu[i*pri[j]]=-miu[i];
			else break;
		}
	}
	for(int i=2;i<maxn;++i)if(!vis[i])
		for(int j=1;i*j<maxn;++j)
			sum[i*j]+=miu[j];
	for(int i=2;i<maxn;++i)sum[i]+=sum[i-1];
}
inline int get(int n,int l){
	return n/(n/l);
}
int main(){
	Init();
	int T;scanf("%d",&T);
	while(T--){
		int n,m;
		scanf("%d%d",&n,&m);
		long long ans=0;
		for(int l=1,r;l<=n&&l<=m;l=r+1){
			r=Min(get(n,l),get(m,l));
			ans+=(sum[r]-sum[l-1])*(n/l)*(m/l);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

双倍经验

posted @ 2021-07-27 19:47  7103  阅读(91)  评论(0)    收藏  举报