您的位置:首页 > 其它

[BZOJ3994][SDOI2015]约数个数和

2016-02-04 15:01 281 查看

[SDOI2015]约数个数和

Description

设d(x)为x的约数个数,给定N、M,求∑ni=1∑mj=1d(ij)\sum_{i=1}^n\sum_{j=1}^md(ij)

Input

输入文件包含多组测试数据。

第一行,一个整数T,表示测试数据的组数。

接下来的T行,每行两个整数N、M。

Output

T行,每行一个整数,表示你所求的答案。

Sample Input

2

7 4

5 6

Sample Output

110

121

HINT

1<=N, M<=50000

1<=T<=50000

Solution

有一个结论:

∑ni=1∑mj=1d(ij)=∑ni=1∑mj=1⌊ni⌋⌊mj⌋[gcd(i,j)==1]\sum_{i=1}^n\sum_{j=1}^md(ij)=\sum_{i=1}^n\sum_{j=1}^m\lfloor\frac n i\rfloor\lfloor\frac m j\rfloor[\gcd(i,j)==1]

然后随便反演就行

【有谁能告诉我这结论是怎么想到的。。

Code

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int MaxN = 50010;

int n,m;
LL miu[MaxN],d[MaxN],c[MaxN];
int prime[MaxN],flag[MaxN],cnt;

inline void kyuu(){
miu[1]=d[1]=1;
for(int i=2;i<=50000;i++){
if(!flag[i]) prime[++cnt]=i,miu[i]=-1,d[i]=2,c[i]=1;
for(int j=1;j<=cnt && prime[j]*i<=50000;j++){
flag[i*prime[j]]=1;
if(i%prime[j]==0){
miu[i*prime[j]]=0;
d[i*prime[j]]=d[i]/(c[i]+1)*(c[i]+2);
c[prime[j]*i]=c[i]+1;
break;
}
miu[i*prime[j]]=-miu[i];
d[i*prime[j]]=d[i]*2;
c[prime[j]*i]=1;
}
}
for(int i=2;i<=50000;i++) miu[i]+=miu[i-1],d[i]+=d[i-1];
}

int main()
{
int T=0;
kyuu();
for(scanf("%d",&T);T--;){
scanf("%d%d",&n,&m);
LL res=0;
for(int i=1,t;i<=n && i<=m;i=t+1)
t=min(n/(n/i),m/(m/i)),res+=(miu[t]-miu[i-1])*d[n/i]*d[m/i];
printf("%lld\n",res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: