题目描述
给定 \(N,M\),求 \(1\le x\le N,1<=y<=M\) 且 \(gcd(x, y)\) 为质数的 \((x, y)\) 有多少对
其中 $T \le 10^4,N\le 10^7,M\le 10^7 $
链接
题解
算法1(暴力)
枚举 \(x\), \(y\), 判断 \(gcd(x,y)\) 是否为质数
欧拉筛预处理出所有的质数
时间复杂度 \(O(NMlogx)\)
不是很优秀
算法2(莫比乌斯反演)
显然可以用莫比乌斯反演
\[ Ans=\sum_{p\in prime,p\le min(n,m)}\sum_{x=1}^{n}\sum_{y=1}^{m}[gcd(x,y)=p] \]
用莫比乌斯反演的套路将原始化简为:
\[ Ans=\sum_{p\in prime,p\le min(n,m)}\sum_{x=1}^{\frac np}\sum_{y=1}^{\frac mp}[gcd(x,y)=1] \]
利用 \(\mu\) 函数的性质展开:
\[ Ans=\sum_{p\in prime,p\le min(n,m)}\sum_{x=1}^{\frac np}\sum_{y=1}^{\frac mp}\sum_{d|gcd(x,y)}\mu(d) \]
继续化简:
\[ Ans=\sum_{p\in prime,p\le min(n,m)}\sum_{d=1}^{min(\frac np,\frac mp)}\mu(d)\cdot\frac n{dp}\cdot\frac m{dp} \]
似乎挺优美的,但是还没有结束:
\(dp\) 感觉很不爽,于是我们枚举 \(T\) 等于 \(dp\)
\[ Ans=\sum_{T=1}^{min(n,m)}\frac nT\cdot\frac mT\cdot\sum_{p\in prime,p\le min(n,m)}\mu(\frac Tp) \]
其中 \(\sum\mu(\frac Tp)\) 可以预处理出来,数论分块一下就好了
时间复杂度 \(O(n\sqrt n)\)
然后就没有然后了
为了增加可读性,没有卡常
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef int INT;
#define int long long
const int MAXN=10000005;
int T;
int n,m,ans;
int p[MAXN],g[MAXN],mu[MAXN],sum[MAXN];
bool v[MAXN];
inline void sieve(){
v[0]=v[1]=1,mu[1]=1;
for (int i=2;i<MAXN;i++){
if (!v[i]){
p[++p[0]]=i;
mu[i]=-1;
}
for (int j=1;j<=p[0] && i*p[j]<MAXN;j++){
v[i*p[j]]=1;
if (i%p[j]==0){
break;
} else{
mu[i*p[j]]=-mu[i];
}
}
}
for (int j=1;j<=p[0];j++)
for (int i=1;i*p[j]<MAXN;i++)
g[i*p[j]]+=mu[i];
for (int i=1;i<MAXN;i++)
sum[i]=sum[i-1]+g[i];
}
INT main(){
sieve();
for (scanf("%lld",&T);T;T--){
scanf("%lld%lld",&n,&m); ans=0;
if (m<n) n^=m^=n^=m;
for (int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(sum[r]-sum[l-1])*(n/l)*(m/l);
}
printf("%lld\n",ans);
}
return 0;
}
后记
初学莫比乌斯反演,公式极可能有打错,有问题请告诉我,谢谢