题目链接:bzoj3994
题目大意:
设d(x)为x的约数个数,给定N、M,求 ∑ni=1∑mj=1d(i∗j)
题解:
莫比乌斯反演
−−−−−−
公式: d(i∗j)=∑x|i∑y|j[gcd(x,y)=1]
证明转自http://blog.csdn.net/clover_hxy/article/details/51282493 修改了一下变量名
证明如下:我们知道了这个自变量的乘积拆分形式,那么如果我们枚举 i 的所有约数 x ,枚举 j 的所有约数 y ,那么 x∗y 一定是 i∗j 的一个约数,于是所有的 x∗y 就包括了 ij 的所有约数,那么我们只要知道有多少不同的 x∗y 就可以了。为了知道不同的 x∗y ,我们可以考虑如何去掉重复的 x∗y 。这里我们考虑把 x 和 y 分为互质和不互质两种情况,设 gcd(x,y)=k ,于是 x=p∗k , y=q∗k 。那么 x∗y 就可以重新组合成两个互质数的积 p∗k∗k 和 q ,而这两个数也分别是 i 和 j 的约数,即合法的 x 和 y 。这一点说明了一个问题:如果枚举到的 x 和 y 不互质,那么 x∗y 这个数一定可以由另外一对互质的 x′ 和 y′ 表示,也就是这一对 x 和 y 是重复的;而当 x 和 y 互质的时候, p∗k∗k 和 q 显然就是 x 和 y ,所以它是唯一的。于是我们总结一下上面的结论:所有 x 和 y 的积包括了 i∗j 的所有约数,当 x 和 y 不互质时, x∗y 可以由另一对互质的 x′ 和 y′ 表示。所以我们得到所有互质的 x 和 y 的乘积就不重复地包含了 ij 的所有约数。
−−−−−−
所以要求的式子即为:
嗯,这道题我经历了从11s到2s的蜕变。还是学了点东西的。
一开始不知道 d(i) 可以直接线性筛于是打了个分块计算,而且懒直接全部改成LL跑成了11s,然后把不必要的改回int后直接跳到了6s。但是我翻记录,发现大部分都是两秒多。看了别人的才知道 d(i) 是可以线性筛的。
//最后推荐一篇总结http://blog.csdn.net/loi_dqs/article/details/50539123
//屏蔽里的是原来求 d(i) 时的分块打法
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
#define N 50100
bool ispri[N];
int cnt,pri[N/4];LL mu[N],d[N],ct[N];
//ct[i]表示i的最小质因数的指数
//d[i]表示i的约数个数 [-后变其前缀和
int mymin(int x,int y){return (xvoid mobius(int lim)
{
cnt=0;mu[1]=1;d[1]=1;
for (int i=2;i<=lim;i++)
{
if (!ispri[i]) {pri[++cnt]=i;mu[i]=-1;d[i]=2;ct[i]=1;}
for (int j=1;j<=cnt && i*pri[j]<=lim;j++)
{
int k=i*pri[j];
ispri[k]=true;
if (i%pri[j]==0)
{
mu[k]=0;ct[k]=ct[i]+1;
d[k]=d[i]/(ct[i]+1)*(ct[k]+1);
break;
}
mu[k]=-mu[i];
ct[k]=1;d[k]=d[i]*2;
}
}
for (int i=2;i<=lim;i++) mu[i]+=mu[i-1],d[i]+=d[i-1];
}
// void pre(int lim)
// {
// int n,i,x,r;
// for (n=1;n<=lim;n++)
// {
// d[n]=0;
// for (i=1;i<=n;i=r+1)
// {
// x=n/i;r=mymin(n,n/x);
// d[n]+=(LL)(r-i+1)*x;
// }
// }
// }
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int T,n,m,lim,x,y,lx,ly,i,r;
scanf("%d",&T);
mobius(50000);//pre(50000);
while (T--)
{
scanf("%d%d",&n,&m);
lim=mymin(n,m);LL ans=0;
for (i=1;i<=lim;i=r+1)
{
x=n/i;y=m/i;
lx=n/x;ly=m/y;
r=mymin(lx,ly);
ans+=d[x]*d[y]*(mu[r]-mu[i-1]);
}
printf("%lld\n",ans);
}
return 0;
}