【bzoj3994】【SDOI2015】约数个数和【数论】【反演】

本文深入探讨了一个看似复杂的数学问题,并通过巧妙的方法将其简化。作者详细介绍了如何运用数学技巧,将原始问题转化为更易于解决的形式。通过引入特定的函数和公式,作者展示了如何在不牺牲精确度的情况下,大幅度提升计算效率。此外,还提供了具体的代码实现,展示了如何利用线性筛等技术优化算法,使其在实际应用中表现优异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

虽然题目上写了反演但是我不知道什么是反演……如果你把Sigma调换位置叫做反演的话。
这道题题面非常简单:
d(x)d(x)d(x)为正整数xxx的约数个数,给定N,MN, MN,M
∑i=1N∑j=1Md(ij)\sum_{i=1}^N\sum_{j=1}^Md(ij)i=1Nj=1Md(ij)
当时我too naive,看到这玩意就默默地打50分暴力去了。。。
今天江苏神犇们做了这道题,我顺便听明白了~~
首先它不知用什么精妙的办法(可能我以后会知道),推出了
∑i=1N∑j=1Md(ij)=∑i=1N∑j=1M⌊Ni⌋⌊Mi⌋[gcd(i,j)==1]\sum_{i=1}^N\sum_{j=1}^Md(ij)= \sum_{i=1}^N\sum_{j=1}^M\left\lfloor\frac Ni\right\rfloor\left\lfloor\frac Mi\right\rfloor[gcd(i,j)==1]i=1Nj=1Md(ij)=i=1Nj=1MiNiM[gcd(i,j)==1]
证明办法是做二阶差分,

F(N,M):=∑i=1N∑j=1Md(ij) ,G(N,M):=∑i=1N∑j=1M⌊Ni⌋⌊Mi⌋[gcd(i,j)==1]=∑i=1∞∑j=1∞⌊Ni⌋⌊Mi⌋[gcd(i,j)==1] (这两个等价,∵∀i(>N),⌊N/i⌋==0)\begin{aligned} F(N,M)&:=\sum_{i=1}^N\sum_{j=1}^Md(ij)\, ,\\ G(N,M)&:=\sum_{i=1}^N\sum_{j=1}^M\left\lfloor\frac Ni\right\rfloor\left\lfloor\frac Mi\right\rfloor[gcd(i,j)==1] \\ &=\sum_{i=1}^{\infty}\sum_{j=1}^\infty\left\lfloor\frac Ni\right\rfloor\left\lfloor\frac Mi\right\rfloor[gcd(i,j)==1]\,(这两个等价,\because \forall i(>N), \lfloor N/i\rfloor==0) \end{aligned}F(N,M)G(N,M):=i=1Nj=1Md(ij),:=i=1Nj=1MiNiM[gcd(i,j)==1]=i=1j=1iNiM[gcd(i,j)==1](i(>N),N/i==0)
则(二阶差分在这里
d(N×M)=F(N,M)−F(N−1,M)−F(N,M−1)+F(N−1,M−1)\begin{aligned} d(N\times M)=F(N,M)&-F(N-1,M)\\ &-F(N,M-1)+F(N-1,M-1) \end{aligned}d(N×M)=F(N,M)F(N1,M)F(N,M1)+F(N1,M1)

G(N,M)−G(N−1,M)−G(N,M−1)+G(N−1,M−1)=∑i=1∞∑j=1∞(⌊Ni⌋−⌊N−1i⌋)(⌊Mi⌋−⌊M−1i⌋)[gcd(i,j)==1]\begin{aligned} &G(N,M)-G(N-1,M)-G(N,M-1)+G(N-1,M-1) \\=&\sum_{i=1}^{\infty}\sum_{j=1}^\infty \left(\left\lfloor\frac Ni\right\rfloor-\left\lfloor\frac {N-1}i\right\rfloor\right) \left(\left\lfloor\frac Mi\right\rfloor-\left\lfloor\frac {M-1}i\right\rfloor\right) [gcd(i,j)==1] \end{aligned}=G(N,M)G(N1,M)G(N,M1)+G(N1,M1)i=1j=1(iNiN1)(iMiM1)[gcd(i,j)==1]
考虑G的二阶差分的意义。
(⌊Ni⌋−⌊N−1i⌋)\left(\left\lfloor\frac Ni\right\rfloor-\left\lfloor\frac {N-1}i\right\rfloor\right)(iNiN1)只有当i∣Ni|NiN的时候才为111(⌊Mi⌋−⌊M−1i⌋)\left(\left\lfloor\frac Mi\right\rfloor-\left\lfloor\frac {M-1}i\right\rfloor\right)(iMiM1)同理。
即G的二阶差分可理解为满足1≤i≤N,1≤j≤M,gcd(i,j)==1,且i∣N,j∣M1\le i \le N,1 \le j \le M,gcd(i,j)==1,且i|N,j|M1iN1jMgcd(i,j)==1iNjM的有序数对(i,j)(i,j)(i,j)的个数。由于i,ji, ji,j分别是N,MN, MN,M的约数,因此对于任意两个不同的质因子p,qp, qp,qi,ji, ji,j的选择方案是互不影响的。
因此,可考虑N×MN\times MN×M的任一质因子ppp,设x,yx, yx,y分别是满足px∣i,py∣jp^x|i,p^y|jpxipyj的最大整数。可以得出,质因子ppp在等式左边的选法数为x+y+1x+y+1x+y+1,而在等式右边的选法数也是x+y+1x+y+1x+y+1(当i,ji,ji,j其中任意一者含有质因子ppp时,另一个就不可以含有质因子ppp)。
故等式成立。
继续对该式进行变换(不失一般性,设 N≤MN\le MNM),
F(N,M)=G(N,M)=∑i=1N∑j=1M⌊Ni⌋⌊Mi⌋[gcd(i,j)==1]=∑i=1N∑j=1M⌊Ni⌋⌊Mi⌋∑d∣gcd(i,j)μ(d)=∑d=1Nμ(d)∑i=1⌊N/d⌋∑j=1⌊M/d⌋⌊Nid⌋⌊Mjd⌋=∑d=1Nμ(d)∑i=1⌊N/d⌋⌊Nid⌋∑j=1⌊M/d⌋⌊Mjd⌋\begin{aligned} F(N,M)&=G(N,M) \\ &=\sum_{i=1}^N\sum_{j=1}^M\left\lfloor\frac Ni\right\rfloor\left\lfloor\frac Mi\right\rfloor[gcd(i,j)==1] \\ &=\sum_{i=1}^N\sum_{j=1}^M\left\lfloor\frac Ni\right\rfloor\left\lfloor\frac Mi\right\rfloor\sum_{d|gcd(i,j)}\mu(d) \\ &=\sum_{d=1}^N\mu(d)\sum_{i=1}^{\lfloor N/d\rfloor}\sum_{j=1}^{\lfloor M/d\rfloor}\left\lfloor\frac N{id}\right\rfloor\left\lfloor\frac M{jd}\right\rfloor \\ &=\sum_{d=1}^N\mu(d)\sum_{i=1}^{\lfloor N/d\rfloor}\left\lfloor\frac N{id}\right\rfloor\sum_{j=1}^{\lfloor M/d\rfloor}\left\lfloor\frac M{jd}\right\rfloor \end{aligned} F(N,M)=G(N,M)=i=1Nj=1MiNiM[gcd(i,j)==1]=i=1Nj=1MiNiMdgcd(i,j)μ(d)=d=1Nμ(d)i=1N/dj=1M/didNjdM=d=1Nμ(d)i=1N/didNj=1M/djdM
g(n):=∑i=1n⌊ni⌋g(n):=\sum_{i=1}^n\left\lfloor\frac ni\right\rfloorg(n):=i=1nin
F(N,M)F(N,M)F(N,M)可进一步化简为F(N,M)=∑d=1Nμ(d)g(⌊Nid⌋)g(⌊Mjd⌋)F(N,M)=\sum_{d=1}^N\mu(d)g\left(\left\lfloor\frac N{id}\right\rfloor\right)g\left(\left\lfloor\frac M{jd}\right\rfloor\right)F(N,M)=d=1Nμ(d)g(idN)g(jdM)
可以发现ggg函数其实就是ddd函数的前缀和,于是可以线性筛出来。
至于约数个数怎么线性筛,只要记录一下每个数,他的素因子分解式中最小素因子的次数c[i]即可。

void genPrime(int n){
	memset(isprime,true,sizeof isprime);
	mu[1]=d[1]=c[1]=1;
	for(int i=2;i<=n;++i){
		if(isprime[i]){
			prime[tot++]=i;
			mu[i]=-1;
			c[i]=1;
			d[i]=2;
		}
		for(int j=0;j<tot&&i*prime[j]<=n;++j){
			isprime[i*prime[j]]=false;
			if(i%prime[j]==0){
				d[i*prime[j]]=d[i]/(c[i]+1)*(c[i]+2);
				c[i*prime[j]]=c[i]+1;break;
			}
			mu[i*prime[j]]=-mu[i];
			d[i*prime[j]]=d[i]*d[prime[j]];
			c[i*prime[j]]=1;
		}
	}
}

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
const int maxn=50001;
int tot,prime[30001],mu[maxn],c[maxn];
ll d[maxn];
bool isprime[maxn];
ll Ans[101][101];
void genPrime(int n){
	memset(isprime,true,sizeof isprime);
	mu[1]=d[1]=c[1]=1;
	for(int i=2;i<=n;++i){
		if(isprime[i]){
			prime[tot++]=i;
			mu[i]=-1;
			c[i]=1;
			d[i]=2;
		}
		for(int j=0;j<tot&&i*prime[j]<=n;++j){
			isprime[i*prime[j]]=false;
			if(i%prime[j]==0){
				d[i*prime[j]]=d[i]/(c[i]+1)*(c[i]+2);
				c[i*prime[j]]=c[i]+1;break;
			}
			mu[i*prime[j]]=-mu[i];
			d[i*prime[j]]=d[i]*d[prime[j]];
			c[i*prime[j]]=1;
		}
	}
	for(int i=1;i<=n;++i) mu[i]+=mu[i-1];
	for(int i=1;i<=n;++i) d[i]+=d[i-1];
}
inline int read(){
	int x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=x*10+ch-48,ch=getchar();
	return x;
}
char a[18];
inline void print(ll x){
	a[0]=0;
	while(x) a[++a[0]]=x%10,x/=10;
	for(;a[0];--a[0])
		putchar(a[a[0]]+48);
	putchar('\n');
}
int main(){
	genPrime(50000);
	int t=read();
	while(t--){
		int n=read(),m=read();
		if(n<=100&&m<=100){
			if(Ans[n][m]){
				print(Ans[n][m]);
				continue;
			}
		}
		if(n>m) swap(n,m);
		ll ans=0;
		for(int i=1,nex;i<=n;i=nex+1){
			nex=min(n/(n/i),m/(m/i));
			ans+=(mu[nex]-mu[i-1])*d[n/i]*d[m/i];
		}
		if(n<=100&&m<=100) Ans[n][m]=Ans[m][n]=ans;
		print(ans);
	}
	return 0;
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值