@xzyxzy
2018-08-15T16:40:45.000000Z
字数 2838
阅读 1459
题解
首先感谢yyb的题解让我大概懂了做法
然后感谢syc的讲解让我明白的关键要点
反演的题,从yyb那里看下大概流程,然后这里讲两个地方
一个数唯一分解为,则
inline void Sieve()
{
ispri[1]=1;p[1]=1;d[1]=1;
for(RG int i=2;i<=MAXN;i++)
{
if(!ispri[i]){pri[++tot]=i;p[i]=1;d[i]=2;}
for(RG int j=1;j<=tot&&i*pri[j]<=MAXN;j++)
{
ispri[i*pri[j]]=1;
if(i%pri[j]==0)
{
d[i*pri[j]]=d[i]/(p[i]+1)*(p[i]+2);//d[i]表示i的因数个数
p[i*pri[j]]=p[i]+1;//p[i]表示i唯一分解后最小质因子的次数
break;
}
d[i*pri[j]]=d[i]*d[pri[j]];//实际上就是d[i]*2
p[i*pri[j]]=1;
}
}
}
这样子预处理,处理询问,总复杂度
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define RG register
#define ll long long
using namespace std;
inline int read()
{
RG char ch=getchar();
RG int h=0;
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9'){h=h*10+ch-'0';ch=getchar();}
return h;
}
const int MAXN=50000;
int mu[MAXN+1],pri[MAXN>>1],tot;
int p[MAXN+1],d[MAXN+1],s[MAXN+1],sd[MAXN+1];
bool ispri[MAXN+1];
inline void Mobius()
{
mu[1]=1;ispri[1]=1;p[1]=1;d[1]=1;
for(RG int i=2;i<=MAXN;i++)
{
if(!ispri[i]){pri[++tot]=i;p[i]=1;mu[i]=-1;d[i]=2;}
for(RG int j=1;j<=tot&&i*pri[j]<=MAXN;j++)
{
ispri[i*pri[j]]=1;
if(i%pri[j]==0)
{
//mu[i*pri[j]]=0;//卡常
d[i*pri[j]]=d[i]/(p[i]+1)*(p[i]+2);//d[i]表示i的因数个数
p[i*pri[j]]=p[i]+1;//p[i]表示i唯一分解后最小质因子的次数
break;
}
mu[i*pri[j]]=-mu[i];
d[i*pri[j]]=d[i]*d[pri[j]];//实际上就是d[i]*2
p[i*pri[j]]=1;
}
}
for(RG int i=1;i<=MAXN;i++)s[i]=s[i-1]+mu[i];
for(RG int i=1;i<=MAXN;i++)sd[i]=sd[i-1]+d[i];
}
int main()
{
RG int T=read();Mobius();
while(T--)
{
RG int N=read(),M=read();
if(N>M)swap(N,M);
RG int l=1,r;RG ll ans=0;
while(l<=N)
{
r=min(N/(N/l),M/(M/l));
ans+=1LL*(s[r]-s[l-1])*sd[N/l]*sd[M/l];
l=r+1;
}
printf("%lld\n",ans);
}
return 0;
}