bzoj3994 约数个数和 数论&莫比乌斯反演

       又是结论题。有一个结论如下:

       d(mn)=Σ(i|m)Σ(j|n) [gcd(i,j)=1]。

       证明:设m=pi^ai(∏是连乘),n=pi^bi,允许一些ai,bi=0但不全为0。一个质因子一个考虑下来。假设这个等式对于m=∏p(i-1)^a(i-1)和n=∏p(i-1)^b(i-1)都成立,现在到了pi,设原来的d为d1,那么由约数个数公式可知,加上质因数pi后d为d1*(ai+bi+1),换句话说左边乘上了(ai+bi+1)。现在考虑右边。那么原来gcd=1的所有(i,j),都有gcd(i,j)=1,gcd(i*pi,j)=1,..gcd(i*pi^ai,j)=1,gcd(i,j*pi)=1,..gcd(i,j*pi^bi)=1,所以右边也乘了(ai+ni+1)等式仍然成立。证毕。

       利用莫比乌斯函数将原式变形为Σ(i=1,m)Σ(j=1,n)Σ(x|i)Σ(y|j)[gcd(x,y)=1]=Σ(i=1,m)Σ(j=1,n)Σ(d|i,d|j) μ(d)[m/i][n/j]=Σμ(d)Σ[m/xd]Σ[n/yd]=Σμ(d)f(m/d)f(n/d),其中f(x)表示Σ(i=1,x)[x/i],可以在1.5阶内算出。

       后来翻到另外一个博客里f(x)表示Σ(i=1,x)d(i),实际上可以线性求出。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 100005
#define ll long long
using namespace std;

int n,m,cnt,mu[N],c[N]; bool prm[N]; ll f[N];
void pfs(){
	int i,j,k; mu[1]=1; memset(prm,1,sizeof(prm));
	for (i=2; i<=50000; i++){
		if (prm[i]){
			c[++cnt]=i; mu[i]=-1;
		}
		for (j=1; j<=cnt; j++){
			if (i*c[j]>50000) break;
			prm[i*c[j]]=0;
			if (i%c[j]) mu[i*c[j]]=-mu[i]; else{
				mu[i*c[j]]=0; break;
			}
		}
	}
	for (i=2; i<=50000; i++) mu[i]+=mu[i-1];
	for (i=1; i<=50000; i++)
		for (j=1; j<=i; j=k+1){
			k=i/(i/j); f[i]+=(ll)(k-j+1)*(i/j);
		}
}
int main(){
	pfs(); int cas; scanf("%d",&cas);
	while (cas--){
		scanf("%d%d",&m,&n); int i,j; ll ans=0;
		for (i=1; i<=m && i<=n; i=j+1){
			j=min(m/(m/i),n/(n/i));
			ans+=f[m/i]*f[n/i]*(mu[j]-mu[i-1]);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值