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)
则
[egin{equation*}
egin{aligned}
ans&= sumlimits_p sumlimits_{p|k} mu(frac{k}{p}) F(k) \
&= sumlimits_p sumlimits_{d=1}^{frac{min(n,m)}{p}} mu(d) lfloor frac{n}{dp}
floor lfloor frac{m}{dp}
floor
end{aligned}
end{equation*}
]
设 (T=dp)
则
[ans=sumlimits_{T=2}^{min(n,m)} lfloor frac{n}{T}
floor lfloor frac{m}{T}
floor sumlimits_{p|T 且p为质数} mu(frac{T}{p})
]
预处理计算每个数 (T) 的 (sumlimits_{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
",ans);
}
return 0;
}