话说这是让我来学莫比乌斯反演的入坑题呢,然而学了莫比乌斯反演还是不会做=_=,连题解都看不懂QAQ
注意事项:
1.数恐症患者慎入!
2.所有除号如果没有作特殊说明,都是向下取整。
3.写的又臭又长,每一步都有一堆啰嗦的解释,因为本蒟蒻每一步都理解了半天(看神犇题解,一个等号看半个小时系列)
4.本蒟蒻发现自己学了假的懵逼钨丝繁衍,所以我重构了一遍这个博客
首先,我们要证明一条结论:
有了上面的结论,我们就可以玩公式变形了!
已经变形的差不多了,再小小变一下得到最终公式:
经过刚才含辛茹苦地淬炼,蒟蒻终于写出一段精简的代码:
#include
#include
#include
#include
using namespace std;
#define ll long long
int read(){
int q=0;char ch=' ';
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')q=q*10+ch-'0',ch=getchar();
return q;
}
const int maxn=50001;
int tot,lim=50000,T,n,m;
int pri[30001],mu[maxn],c[maxn];
ll d[maxn];bool is[maxn];
void init(){
int i,j,k;
mu[1]=c[1]=d[1]=1;
for(i=2;i<=lim;i++){
if(!is[i]){
pri[++tot]=i;mu[i]=-1;
c[i]=1;d[i]=2;
}
for(j=1;j<=tot;j++){
k=pri[j]*i;if(k>lim)break;
is[k]=1;
if(i%pri[j]){ d[k]=d[i]*d[pri[j]];c[k]=1;mu[k]=-mu[i];}//有新的最小质因子了
else {d[k]=d[i]/(c[i]+1)*(c[i]+2);c[k]=c[i]+1;break;}
//d:删去原来的贡献,添加新的贡献
}
}
for(i=2;i<=lim;i++)d[i]=d[i]+d[i-1],mu[i]=mu[i]+mu[i-1];//前缀和
}
int main()
{
int i,j;
init();T=read();
while(T--){
n=read();m=read();
if(n>m)swap(n,m);ll ans=0;
for(i=1;i<=n;i=j+1){
j=min(n/(n/i),m/(m/i));//不懂这句请看我的莫比乌斯反演讲解
ans+=(mu[j]-mu[i-1])*d[n/i]*d[m/i];
}
printf("%lld\n",ans);
}
return 0;
}