Description
神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
Input
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M
Output
T行,每行一个整数表示第i组数据的结果
Sample Input
2
10 10
100 100
Sample Output
30
2791
HINT
T = 10000
N, M <= 10000000
想法
Orz PoPoQQQ大神……
若枚举每个质数 \(p\)
则
\[
\begin{equation*}
\begin{aligned}
ans&= \sum\limits_p \sum\limits_{p|k} \mu(\frac{k}{p}) F(k) \ &= \sum\limits_p \sum\limits_{d=1}^{\frac{min(n,m)}{p}} \mu(d) \lfloor \frac{n}{dp} \rfloor \lfloor \frac{m}{dp} \rfloor
\end{aligned}
\end{equation*}
\]
设 \(T=dp\)
则
\[
ans=\sum\limits_{T=2}^{min(n,m)} \lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor \sum\limits_{p|T 且p为质数} \mu(\frac{T}{p})
\]
预处理计算每个数 \(T\) 的 \(\sum\limits_{p|T 且p为质数} \mu(\frac{T}{p})\) 及其前缀和
用每个质数把自己的倍数筛一遍就行了。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 10000005;
int mu[N];
ll sum[N];
int prime[N],pnum,p[N];
int getmu(){
mu[1]=1;
for(int i=2;i<N;i++) p[i]=1;
for(int i=2;i<N;i++){
if(p[i]) {
prime[pnum++]=i;
mu[i]=-1;
}
for(int j=0;j<pnum && (ll)prime[j]*i<N;j++){
p[i*prime[j]]=0;
if(i%prime[j]==0) {
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=0;i<pnum;i++)
for(int j=1;(ll)j*prime[i]<N;j++)
sum[j*prime[i]]+=mu[j];
sum[1]=0;
for(int i=2;i<N;i++) sum[i]+=sum[i-1];
}
int n,m,T;
int main()
{
getmu();
scanf("%d",&T);
ll ans;
while(T--){
scanf("%d%d",&n,&m);
ans=0;
for(int l=2,r;l<=min(n,m);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;
}