//八中上的权限题,只能上洛谷拷了
题目描述
神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
输入输出格式
输入格式:
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M
输出格式:
T行,每行一个整数表示第i组数据的结果
输入输出样例
输入样例
2
10 10
100 100
输出样例
30
2791
说明
T = 10000
N, M <= 10000000
这道题要求的是 ∑ni=1∑mj=1[gcd(i,j)=p] ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = p ] ( p p 为质数),我们来推一下式子(我们假定)
∑ni=1∑mj=1[gcd(i,j)=p]=∑p∈prime∑npi=1∑mpj=1∑x|gcd(i,j)μ(x)=∑p∈prime∑npx=1μ(x)[npx][mpx] ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = p ] = ∑ p ∈ p r i m e ∑ i = 1 n p ∑ j = 1 m p ∑ x | g c d ( i , j ) μ ( x ) = ∑ p ∈ p r i m e ∑ x = 1 n p μ ( x ) [ n p x ] [ m p x ]
原式的 px p x 确实让人不爽,而且对着这个式子直接做会T,所以我们还得继续推,我们令 T=px T = p x ,则原式
=∑nT=1∑p|T,p∈primeμ(Tp)[nT][mT]=∑nT=1[nT][mT](∑p|T,p∈primeμ(Tp)) = ∑ T = 1 n ∑ p | T , p ∈ p r i m e μ ( T p ) [ n T ] [ m T ] = ∑ T = 1 n [ n T ] [ m T ] ( ∑ p | T , p ∈ p r i m e μ ( T p ) )
前面的部分可以用数论分块直接搞,右边的东西我们可以预处理,我们用线性筛筛出素数,然后计算其倍数,最后统计一个前缀和即可(因为左边是分块,所以右边必须是前缀和的形式)
#include<bits/stdc++.h>
#define MAXN 10000000
#define ll long long
using namespace std;
ll read(){
char c;ll x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
void print(ll x){
if(x/10) print(x/10);
putchar(x%10+'0');
}
int T,n,m,top,l,r,mu[MAXN+5],pri[MAXN+5],vis[MAXN+5];
ll ans,sum[MAXN+5],g[MAXN+5];
int main()
{
T=read();mu[1]=1;
register int i,j;
for(i=2;i<=MAXN;i++){
if(!vis[i]) pri[++top]=i,mu[i]=-1;
for(j=1;j<=top&&pri[j]*i<=MAXN;j++){
vis[pri[j]*i]=1;
if(i%pri[j]==0) break;
mu[i*pri[j]]=-mu[i];
}
}
for(j=1;j<=top;j++)
for(i=1;i*pri[j]<=MAXN;i++) g[i*pri[j]]+=(ll)mu[i];
for(i=1;i<=MAXN;i++) sum[i]=sum[i-1]+g[i];
while(T--){
n=read();m=read();ans=0;
if(n>m) swap(n,m);l=1;
while(l<=n){
r=min(n/(n/l),m/(m/l));r=min(r,n);
ans+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
l=r+1;
}
print(ans);puts("");
}
return 0;
}