BZOJ_3994_[SDOI2015]约数个数和_莫比乌斯反演

Posted fcwww

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ_3994_[SDOI2015]约数个数和_莫比乌斯反演相关的知识,希望对你有一定的参考价值。

BZOJ_3994_[SDOI2015]约数个数和_莫比乌斯反演

Description

 设d(x)为x的约数个数,给定N、M,求  技术分享图片

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

基本同BZOJ4176,需要处理$f_n=\sum\limits_{i=1}n/i$,然后分块求。
 
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
#define N 50050
using namespace std;
ll f[N];
int prime[8080],cnt,miu[N],s[N];
bool vis[N];
void init() {
	int i,j;
	miu[1]=s[1]=1;
	for(i=2;i<=50000;i++) {
		if(!vis[i]) {
			prime[++cnt]=i;
			miu[i]=-1;
		}
		for(j=1;j<=cnt&&i*prime[j]<=50000;j++) {
			vis[i*prime[j]]=1;
			if(i%prime[j]==0) {
				miu[i*prime[j]]=0;
				break;
			}
			miu[i*prime[j]]=-miu[i];
		}
		s[i]=s[i-1]+miu[i];
	}
	int lst;
	for(i=1;i<=50000;i++) {
		for(j=1;j<=i;j=lst+1) {
			lst=i/(i/j); f[i]+=1ll*(lst-j+1)*(i/j);
		}
	}
}
ll calc(ll n,ll m) {
	ll i,lst,r=min(n,m),ans=0;
	for(i=1;i<=r;i=lst+1) {
		lst=min(n/(n/i),m/(m/i));
		ans+=(s[lst]-s[i-1])*f[n/i]*f[m/i];
	}
	return ans;
}
int main() {
	init();
	int T;
	ll n,m;
	scanf("%d",&T);
	while(T--) {
		scanf("%lld%lld",&n,&m);
		printf("%lld\n",calc(n,m));
	}
}

 

 

以上是关于BZOJ_3994_[SDOI2015]约数个数和_莫比乌斯反演的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ3994][SDOI2015]约数个数和

BZOJ3994: [SDOI2015]约数个数和

bzoj3994: [SDOI2015]约数个数和(莫比乌斯反演+分块)

[bzoj3994] [SDOI2015] 约数个数和

BZOJ3994 [SDOI2015]约数个数和

bzoj3994:[SDOI2015]约数个数和