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

7 篇文章 0 订阅
3 篇文章 0 订阅

虽然题目上写了反演但是我不知道什么是反演……如果你把Sigma调换位置叫做反演的话。
这道题题面非常简单:
d ( x ) d(x) d(x)为正整数 x x x的约数个数,给定 N , M N, M N,M
∑ i = 1 N ∑ j = 1 M d ( i j ) \sum_{i=1}^N\sum_{j=1}^Md(ij) i=1Nj=1Md(ij)
当时我too naive,看到这玩意就默默地打50分暴力去了。。。
今天江苏神犇们做了这道题,我顺便听明白了~~
首先它不知用什么精妙的办法(可能我以后会知道),推出了
∑ i = 1 N ∑ j = 1 M d ( i j ) = ∑ i = 1 N ∑ j = 1 M ⌊ N i ⌋ ⌊ M i ⌋ [ g c d ( 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 = 1 N ∑ j = 1 M d ( i j )   , G ( N , M ) : = ∑ i = 1 N ∑ j = 1 M ⌊ N i ⌋ ⌊ M i ⌋ [ g c d ( i , j ) = = 1 ] = ∑ i = 1 ∞ ∑ j = 1 ∞ ⌊ N i ⌋ ⌊ M i ⌋ [ g c d ( 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 ∞ ( ⌊ N i ⌋ − ⌊ N − 1 i ⌋ ) ( ⌊ M i ⌋ − ⌊ M − 1 i ⌋ ) [ g c d ( 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的二阶差分的意义。
( ⌊ N i ⌋ − ⌊ N − 1 i ⌋ ) \left(\left\lfloor\frac Ni\right\rfloor-\left\lfloor\frac {N-1}i\right\rfloor\right) (iNiN1)只有当 i ∣ N i|N iN的时候才为 1 1 1 ( ⌊ M i ⌋ − ⌊ M − 1 i ⌋ ) \left(\left\lfloor\frac Mi\right\rfloor-\left\lfloor\frac {M-1}i\right\rfloor\right) (iMiM1)同理。
即G的二阶差分可理解为满足 1 ≤ i ≤ N , 1 ≤ j ≤ M , g c d ( i , j ) = = 1 , 且 i ∣ N , j ∣ M 1\le i \le N,1 \le j \le M,gcd(i,j)==1,且i|N,j|M 1iN1jMgcd(i,j)==1iNjM的有序数对 ( i , j ) (i,j) (i,j)的个数。由于 i , j i, j i,j分别是 N , M N, M N,M的约数,因此对于任意两个不同的质因子 p , q p, q p,q i , j i, j i,j的选择方案是互不影响的。
因此,可考虑 N × M N\times M N×M的任一质因子 p p p,设 x , y x, y x,y分别是满足 p x ∣ i , p y ∣ j p^x|i,p^y|j pxipyj的最大整数。可以得出,质因子 p p p在等式左边的选法数为 x + y + 1 x+y+1 x+y+1,而在等式右边的选法数也是 x + y + 1 x+y+1 x+y+1(当 i , j i,j i,j其中任意一者含有质因子 p p p时,另一个就不可以含有质因子 p p p)。
故等式成立。
继续对该式进行变换(不失一般性,设 N ≤ M N\le M NM),
F ( N , M ) = G ( N , M ) = ∑ i = 1 N ∑ j = 1 M ⌊ N i ⌋ ⌊ M i ⌋ [ g c d ( i , j ) = = 1 ] = ∑ i = 1 N ∑ j = 1 M ⌊ N i ⌋ ⌊ M i ⌋ ∑ d ∣ g c d ( i , j ) μ ( d ) = ∑ d = 1 N μ ( d ) ∑ i = 1 ⌊ N / d ⌋ ∑ j = 1 ⌊ M / d ⌋ ⌊ N i d ⌋ ⌊ M j d ⌋ = ∑ d = 1 N μ ( d ) ∑ i = 1 ⌊ N / d ⌋ ⌊ N i d ⌋ ∑ j = 1 ⌊ M / d ⌋ ⌊ M j d ⌋ \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 = 1 n ⌊ n i ⌋ g(n):=\sum_{i=1}^n\left\lfloor\frac ni\right\rfloor g(n):=i=1nin
F ( N , M ) F(N,M) F(N,M)可进一步化简为 F ( N , M ) = ∑ d = 1 N μ ( d ) g ( ⌊ N i d ⌋ ) g ( ⌊ M j d ⌋ ) 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)
可以发现 g g g函数其实就是 d d d函数的前缀和,于是可以线性筛出来。
至于约数个数怎么线性筛,只要记录一下每个数,他的素因子分解式中最小素因子的次数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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值