YY的GCD
一.提要
这片题解是一个大的学习笔记中的附属品,其中没有什么变换讲解,如果看不懂请先一步到这篇文章
二.解题
[sumlimits_{pin P}
sumlimits_{x=1}^{n}
sumlimits_{y=1}^m[gcd(x,y)=p]
]
[=sumlimits_{pin P}
sumlimits_{x=1}^{lfloorfrac{n}{p}
floor}
sumlimits_{y=1}^{lfloorfrac{m}{p}
floor}
sumlimits_{d|gcd(x,y)}mu(d)\
]
[=sumlimits_{pin P}
sumlimits_{d=1}^{lfloorfrac{min(n,m)}{p}
floor}
mu(d)lfloorfrac{n}{pd}
floor
lfloorfrac{m}{pd}
floor\
]
[=sumlimits_{t=1}^{min(n,m)}
lfloorfrac{n}{t}
floor
lfloorfrac{m}{t}
floor
sumlimits_{pin P,p|t}mu(frac{t}{p})
]
第二步运用了(mu*1=epsilon)
第三步运用了一个……没有名字的定理来划掉了两个求和(在程序实现的时候需要数论分块解决(lfloorfrac{n}{pd} floor lfloorfrac{m}{pd} floor)的不同取值)
第四步换元,调换顺序
三.CODE
#define ll long long
#define m_for(i,a,b) for(int i=a;i<=b;++i)
inline int read() {
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int MAXN=10000005;
int prime[MAXN],tot,mu[MAXN];
bool vis[MAXN];
void m_p(int x){
mu[1]=1;
m_for(i,2,x){
if(!vis[i])prime[++tot]=i,mu[i]=-1;
for(int j=1;i*prime[j]<=x&&j<=tot;++j){
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
}
}
int g[MAXN];
ll sum[MAXN];
void m_mu(int x){
m_for(i,1,tot){
for(int j=1;j*prime[i]<=x;++j){
g[j*prime[i]]+=mu[j];
}
}
m_for(i,1,x)sum[i]=sum[i-1]+1LL*g[i];
}
int t,n,m;
ll ans;
int main(){
m_p(MAXN);
m_mu(MAXN);
t=read();
while(t--){
n=read();m=read();
if(n>m)swap(n,m);
ans=0;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),min(m/(m/l),n));
ans+=1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]);
//cout<<ans<<endl;
}
cout<<ans<<endl;
}
}