SDOI2015 约数个数和

本文深入探讨了数论函数的性质及应用,详细解析了莫比乌斯反演的推导过程,并通过实例展示了如何利用线性筛法求解约数个数前缀和,为复杂数论问题提供了解决思路。

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

传送门
其实就是一个性质: d ( a b ) = ∑ i ∣ a ∑ j ∣ b [ g c d ( i , j ) = = 1 ] d(ab)=\sum_{i|a}\sum_{j|b}[gcd(i,j)==1] d(ab)=iajb[gcd(i,j)==1]

看到这种两个乘起来的数论函数,处理办法往往都是想方设法把这两个数拆开。比如:
φ ( i j ) = φ ( i ) ∗ φ ( j ) ∗ g c d ( i , j ) φ ( g c d ( i , j ) ) \varphi(ij)=\varphi(i)*\varphi(j)*\frac{gcd(i,j)}{\varphi(gcd(i,j))} φ(ij)=φ(i)φ(j)φ(gcd(i,j))gcd(i,j)

证明可以通过把它们质因数分解得到:
a b = ∏ p i t i , a = ∏ p i a i , b = ∏ p i b i ab=\prod p_i^{t_i},a=\prod p_i^{a_i},b=\prod p_i^{b_i} ab=pitia=piaib=pibi,那么有 t i = a i + b i t_i=a_i+b_i ti=ai+bi
i = ∏ p i x i , j = ∏ p i y i i=\prod p_i^{x_i},j=\prod p_i^{y_i} i=pixij=piyi
由于 g c d ( i , j ) = 1 gcd(i,j)=1 gcd(i,j)=1,那么有: ∀ i , x i = 0    o r    y i = 0 \forall i,x_i=0\ \ or\ \ y_i=0 i,xi=0  or  yi=0
x i = 0 x_i=0 xi=0,那么 y i ∈ [ 0 , b i ] y_i\in[0,b_i] yi[0,bi],共 b i + 1 b_i+1 bi+1种取值。
y i = 0 y_i=0 yi=0,那么 x i ∈ [ 0 , a i ] x_i\in[0,a_i] xi[0,ai],共 a i + 1 a_i+1 ai+1种取值。
x i = 0    a n d    y i = 0 x_i=0\ \ and\ \ y_i=0 xi=0  and  yi=0被算了两次,那么对于一个 i i i x i x_i xi y i y_i yi的取值方案共有 ( a i + 1 ) + ( b i + 1 ) − 1 = a i + b i + 1 (a_i+1)+(b_i+1)-1=a_i+b_i+1 (ai+1)+(bi+1)1=ai+bi+1种。
根据乘法原理,可以得到:
∑ i ∣ a ∑ j ∣ b [ g c d ( i , j ) = = 1 ] \sum_{i|a}\sum_{j|b}[gcd(i,j)==1] iajb[gcd(i,j)==1]
= ∏ ( a i + b i + 1 ) =\prod (a_i+b_i+1) =(ai+bi+1)
= ∏ ( t i + 1 ) =\prod (t_i+1) =(ti+1)
= d ( a b ) =d(ab) =d(ab)
于是得证。
接下来推式子就好:
∑ i = 1 n ∑ j = 1 m d ( i j ) \sum_{i=1}^{n} \sum_{j=1}^{m}d(ij) i=1nj=1md(ij)
= ∑ i = 1 n ∑ j = 1 m ∑ a ∣ i ∑ b ∣ j [ g c d ( a , b ) = = 1 ] =\sum_{i=1}^{n} \sum_{j=1}^{m} \sum_{a|i} \sum_{b|j} [gcd(a,b)==1] =i=1nj=1maibj[gcd(a,b)==1]
莫比乌斯反演:
= ∑ i = 1 n ∑ j = 1 m ∑ a ∣ i ∑ b ∣ j ∑ d ∣ g c d ( a , b ) μ ( d ) =\sum_{i=1}^{n} \sum_{j=1}^{m} \sum_{a|i} \sum_{b|j} \sum_{d|gcd(a,b)} \mu(d) =i=1nj=1maibjdgcd(a,b)μ(d)
= ∑ i = 1 n ∑ j = 1 m ∑ a ∣ i ∑ b ∣ j ∑ d ∣ a , d ∣ b μ ( d ) =\sum_{i=1}^{n} \sum_{j=1}^{m} \sum_{a|i} \sum_{b|j} \sum_{d|a,d|b} \mu(d) =i=1nj=1maibjda,dbμ(d)
交换 a , b a,b a,b i , j i,j i,j的枚举顺序:
= ∑ a = 1 n ∑ b = 1 m ∑ i = 1 ⌊ n a ⌋ ∑ j = 1 ⌊ m b ⌋ ∑ d ∣ a , d ∣ b μ ( d ) =\sum_{a=1}^{n} \sum_{b=1}^{m} \sum_{i=1}^{\lfloor \frac{n}{a} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{b} \rfloor} \sum_{d|a,d|b} \mu(d) =a=1nb=1mi=1anj=1bmda,dbμ(d)
= ∑ a = 1 n ∑ b = 1 m ⌊ n a ⌋ ⌊ m b ⌋ ∑ d ∣ a , d ∣ b μ ( d ) =\sum_{a=1}^{n} \sum_{b=1}^{m} \lfloor \frac{n}{a} \rfloor \lfloor \frac{m}{b} \rfloor \sum_{d|a,d|b} \mu(d) =a=1nb=1manbmda,dbμ(d)
提前枚举 d d d
= ∑ d = 1 n μ ( d ) ∑ a = 1 ⌊ n d ⌋ ∑ b = 1 ⌊ m d ⌋ ⌊ n a ∗ d ⌋ ⌊ m b ∗ d ⌋ =\sum_{d=1}^{n} \mu(d)\sum_{a=1}^{ \lfloor \frac{n}{d} \rfloor} \sum_{b=1}^{ \lfloor \frac{m}{d} \rfloor} \lfloor \frac{n}{a*d} \rfloor \lfloor \frac{m}{b*d} \rfloor =d=1nμ(d)a=1dnb=1dmadnbdm
= ∑ d = 1 n μ ( d ) ∑ a = 1 ⌊ n d ⌋ ⌊ ⌊ n d ⌋ a ⌋ ∑ b = 1 ⌊ m d ⌋ ⌊ ⌊ m d ⌋ b ⌋ =\sum_{d=1}^{n} \mu(d)\sum_{a=1}^{ \lfloor \frac{n}{d} \rfloor} \lfloor \frac{\lfloor \frac{n}{d} \rfloor}{a} \rfloor \sum_{b=1}^{ \lfloor \frac{m}{d} \rfloor}\lfloor \frac{\lfloor \frac{m}{d} \rfloor}{b} \rfloor =d=1nμ(d)a=1dnadnb=1dmbdm
我们令 f ( n ) = ∑ i = 1 n ⌊ n i ⌋ f(n)=\sum_{i=1}^{n} \lfloor \frac{n}{i} \rfloor f(n)=i=1nin
f f f其实就是约数个数前缀和,而约数个数函数可以线性筛。筛完之后求个前缀和就行了。详情看这里
其实如果不知道这个东西的筛法,整除分块预处理也是可以的。

答案即为:
a n s = ∑ d = 1 n μ ( d ) ∗ f ( n d ) ∗ f ( m d ) ans=\sum_{d=1}^{n} \mu(d)*f(\frac{n}{d})*f(\frac{m}{d}) ans=d=1nμ(d)f(dn)f(dm)
n d \frac{n}{d} dn最多有 n \sqrt n n 种取值, m d \frac{m}{d} dm最多有 m \sqrt m m 种取值,所以整除分块一共最多有 ( n + m ) (\sqrt n +\sqrt m) (n +m )种取值,总复杂度 O ( n + T ∗ ( n + m ) ) O(n+T*(\sqrt n+\sqrt m)) O(n+T(n +m ))。代码中 D D D是约数个数函数。 m u mu mu D D D都记的是前缀和

#include<bits/stdc++.h>
#define re register
#define ll long long
using namespace std;
const int N=5e4+10;
int T,n,m;ll ans,D[N];
int mark[N],mu[N],num[N],P[N],cnt=0;
inline void linear_sieves(){
	mark[1]=mu[1]=D[1]=1;
	for(int i=2;i<N;++i){
		if(!mark[i]) P[++cnt]=i,D[i]=2,num[i]=1,mu[i]=-1;
		for(int j=1;j<=cnt&&i*P[j]<N;++j){
			mark[i*P[j]]=1;
			if(i%P[j]) mu[i*P[j]]=-mu[i],D[i*P[j]]=D[i]*2,num[i*P[j]]=1;
			else{
				mu[i*P[j]]=0,num[i*P[j]]=num[i]+1;
				D[i*P[j]]=D[i]/(num[i]+1)*(num[i]+2);
				break;
			}
		}mu[i]+=mu[i-1],D[i]+=D[i-1];
	}
}
int main(){
	linear_sieves(),scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m),ans=0;
		for(int re d=1,nxd;d<=min(n,m);d=nxd+1)
			nxd=min(n/(n/d),m/(m/d)),
			ans+=(mu[nxd]-mu[d-1])*D[n/d]*D[m/d];
		printf("%lld\n",ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值