BZOJ 2820 - YY的GCD(莫比乌斯反演)
题目链接 https://cn.vjudge.net/problem/HYSBZ-2820
【题目描述】
神犇YY虐完数论后给傻×kAc出了一题
给定,求且为质数的有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
【输入格式】
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M
【输出格式】
T行,每行一个整数表示第i组数据的结果
【样例输入】
2
10 10
100 100
【样例输出】
30
2791
【思路】
贴一篇大佬的题解,太强了 BZOJ2820
本菜鸡差不多照猫画虎抄了一遍代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=10000005;
bool vis[maxn];
int prim[maxn];
int mu[maxn];
ll g[maxn],sum[maxn];
int cnt;
void get_mu(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
prim[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt && prim[j]*i<=n;j++){
vis[prim[j]*i]=1;
if(i%prim[j]==0) break;
else mu[i*prim[j]]=-mu[i];
}
}
for(int j=1;j<=cnt;++j){
for(int i=1;i*prim[j]<=n;++i){
g[i*prim[j]]+=mu[i];
}
}
for(int i=1;i<=n;++i) sum[i]=sum[i-1]+g[i];
}
int main(){
get_mu(maxn-1);
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
ll ans=0;
for(int L=1,R;L<=n;L=R+1){
R=min(n/(n/L),m/(m/L));
ans+=(sum[R]-sum[L-1])*(ll)(n/L)*(ll)(m/L);
}
printf("%lld\n",ans);
}
return 0;
}