luogu P2257 YY的GCD |莫比乌斯反演

题目描述

神犇 YY 虐完数论后给傻× kAc 出了一题

给定 \(N, M\),求 \(1 \leq x \leq N\)\(1 \leq y \leq M\)\(\gcd(x, y)\) 为质数的 \((x, y)\) 有多少对。

输入格式

第一行一个整数 \(T\) 表述数据组数。

接下来 \(T\) 行,每行两个正整数,\(N, M\)

输出格式

\(T\) 行,每行一个整数表示第 \(i\) 组数据的结果。


#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1e7+10,M=5e4;
#define ll long long
inline int read(){
	int x=0; char c=getchar();
	while(c<'0'|c>'9')c=getchar();
	while('0'<=c&&c<='9'){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); }
	return x;
}
ll mu[N],pri[N],f[N],tot;
bool vis[N];
inline void mubius(int n){
	mu[1]=vis[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){ pri[++tot]=i; mu[i]=-1; }
		for(int j=1;j<=tot&&pri[j]*i<=n;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j])mu[i*pri[j]]=-mu[i];
			else { mu[i*pri[j]]=0; break;  }
		}
	}
	for(int i=1;i<=tot;i++)
	for(int j=1;pri[i]*j<=n;j++)
	f[j*pri[i]]+=mu[j];
	for(int i=1;i<=n;i++)f[i]+=f[i-1];
}
signed main(){
	int T=read(),n,m; 
	mubius(1e7);
	while(T--){
		n=read(),m=read();
		ll ans=0;
		int lim=min(n,m);
		for(int i=1,j=0;i<=lim;i=j+1){
			j=min(n/(n/i),m/(m/i));
			ans+=(f[j]-f[i-1])*(n/i)*(m/i);
		}
		printf("%lld\n",ans);
	}
}

posted @ 2020-05-28 09:32  白木偶君  阅读(94)  评论(0)    收藏  举报