3994: [SDOI2015]约数个数和
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 898 Solved: 619
[Submit][Status][Discuss]
Description

Input
输入文件包含多组测试数据。
Output
T行,每行一个整数,表示你所求的答案。
Sample Input
7 4
5 6
Sample Output
121
HINT
1<=N, M<=50000
Source
分析:
首先$d(x)$是一个积性函数,其次这个东西有一个很神奇的性质:
$d(nm)=sum _{xmid n} sum _{ymid m} [gcd(x,y)==1]$
证明如下:(懒得写了...公式打起来好麻烦...直接摘抄Sengxian的解释...QwQ)

于是接下来就直接莫比乌斯反演就好了...
$sum _{x=1}^{n} sum _{y=1}^{m} left lfloor frac{n}{x} ight floor left lfloor frac{m}{y} ight floor sum _{dmid x dmid y}mu (d)$
$=sum _{d=1}^{x} mu(d) sum _{i=1}^{frac {n}{d}} left lfloor frac{n}{id} ight floor sum _{j=1}^{frac {m}{d}} left lfloor frac{m}{jd} ight floor$
现在有一个有用的公式:
$left lfloor frac{n}{xy} ight floor=left lfloor frac{ left lfloor frac{n}{x} ight floor }{y} ight floor$
于是乎,我们定义$f(x)=sum _{i=1}^{x} left lfloor frac{x}{i} ight floor$,
那么式子就变成酱紫:
$sum _{d=1}^{n} mu(d) f(left lfloor frac{n}{d} ight floor) f(left lfloor frac{m}{d} ight floor)$
时间复杂度:$O(Nsqrt{N}+Tsqrt{N})$
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=50000+5;
int n,m,cas,cnt,mu[maxn],pri[maxn],vis[maxn];
long long ans,f[maxn];
inline long long calc(int x){
long long res=0;
for(int i=1,r;i<=x;i=r+1){
r=x/(x/i);
res+=(x/i)*(r-i+1);
}
return res;
}
inline void prework(void){
mu[1]=1;
for(int i=2;i<=50000;i++){
if(!vis[i])
vis[i]=1,pri[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*pri[j]<=50000;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0){
mu[i*pri[j]]=0;break;
}
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=50000;i++) mu[i]+=mu[i-1],f[i]=calc(i);
}
signed main(void){
scanf("%d",&cas);prework();
while(cas--){
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);ans=0;
for(int i=1,r;i<=n;i=r+1){
r=min(n/(n/i),m/(m/i));
ans+=f[n/i]*f[m/i]*(mu[r]-mu[i-1]);
}
printf("%lld
",ans);
}
return 0;
}
By NeighThorn