BZOJ 2820 YY的GCD
跟着litble学套路
Solution
题目要求
开始疯狂套路
0x00
首先枚举
0x01
接着将
变为
0x02
其次我们通过莫比乌斯函数的性质
将 转化为 ,即
0x03
下一步枚举
同时
也会变形,变为枚举
的倍数
0x04
设
,枚举
0x05
设
,用线性筛将其处理出来
后面利用分块+前缀和在 时间内处理出来
搞定!
代码如下
#include <bits/stdc++.h>
using namespace std;
const int N = 10000005;
int pri[N],tot,mu[N],n,m,t;
long long f[N];
bool mark[N];
void get() {
mu[1]=1;
for(int i=2;i<=10000000;++i) {
if(!mark[i]) {
pri[++tot]=i;
mu[i]=-1;
}
for(int j=1;j<=tot && pri[j]*i<=10000000;++j) {
mark[i*pri[j]]=1;
if(i%pri[j]==0) break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=tot;++i)
for(int j=1;j*pri[i]<=10000000;++j)
f[pri[i]*j]+=mu[j];
for(int i=1;i<=10000000;++i)
f[i]+=f[i-1];
}
long long cal() {
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
int pos=0;
long long ans=0;
for(int i=1;i<=n;i=pos+1) {
pos=min(n/(n/i),m/(m/i));
ans+=(f[pos]-f[i-1])*(n/i)*(m/i);
}
return ans;
}
int main() {
get();
scanf("%d",&t);
while(t--)
printf("%lld\n",cal());
return 0;
}