[SDOI2015][bzoj 3994][Luogu P3327] 约数个数和 (莫比乌斯反演)

题目描述

d ( x ) d(x) d(x) x x x的约数个数,给定 N N N M M M,求 ∑ i = 1 N ∑ j = 1 M d ( i j ) \sum^{N}_{i=1}\sum^{M}_{j=1} d(ij) i=1Nj=1Md(ij)
N , M , T < = 50000 N,M,T<=50000 N,M,T<=50000

题目分析

首先很不显然的有这样一个结论:
d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[(x,y)==1] d(ij)=xiyj[(x,y)==1]

证明如下

将一个数唯一质因数分解为 p 1 k 1 p 2 k 2 p 3 k 3 . . . p n k n p_1^{k_1}p_2^{k_2}p_3^{k_3}...p_n^{k_n} p1k1p2k2p3k3...pnkn,其约数个数为 ( k 1 + 1 ) ( k 2 + 1 ) ( k 3 + 1 ) . . . ( k n + 1 ) (k_1+1)(k_2+1)(k_3+1)...(k_n+1) (k1+1)(k2+1)(k3+1)...(kn+1)

考虑一个质数 p p p d ( i j ) d(ij) d(ij)的影响,假设 i i i分解质因数后有 k k k p p p, j j j分解质因数后有 q q q p p p,则产生的贡献即为 k + q + 1 k+q+1 k+q+1,接下来是关键的一步(反正我想不到XD)
k + q + 1 = ∑ x = 0 k ∑ y = 0 q [ ( p x , p y ) = = 1 ] k+q+1=\sum_{x=0}^k\sum_{y=0}^q[(p^x,p^y)==1] k+q+1=x=0ky=0q[(px,py)==1]

(此句可自行忽略:只有当 x y = 0 xy=0 xy=0时才会有值,这就相当于一个 ( k + 1 ) ∗ ( q + 1 ) (k+1)∗(q+1) (k+1)(q+1)的矩形,只取了左下角的 L L L字型的一块)

根据乘法原理,有
d ( i j ) = ∑ x 1 = 0 k 1 ∑ y 1 = 0 q 1 [ ( p 1 x 1 , p 1 y 1 ) = = 1 ] ∗ ∑ x 2 = 0 k 2 ∑ y 2 = 0 q 2 [ ( p 2 x 2 , p 2 y 2 ) = = 1 ] ⋅ ⋅ ⋅ ∗ ∑ x n = 0 k n ∑ y n = 0 q n [ ( p n x n , p n y n ) = = 1 ] d(ij)=\sum_{x_1=0}^{k_1}\sum_{y_1=0}^{q_1}[(p_1^{x_1},p_1^{y_1})==1]\newline *\sum_{x_2=0}^{k_2}\sum_{y_2=0}^{q_2}[(p_2^{x_2},p_2^{y_2})==1]\newline ···\newline *\sum_{x_n=0}^{k_n}\sum_{y_n=0}^{q_n}[(p_n^{x_n},p_n^{y_n})==1] d(ij)=x1=0k1y1=0q1[(p1x1,p1y1)==1]x2=0k2y2=0q2[(p2x2,p2y2)==1]xn=0knyn=0qn[(pnxn,pnyn)==1]
因为必须满足所有 ( p n x n , p n y n ) = = 1 (p_n^{x_n},p_n^{y_n})==1 (pnxn,pnyn)==1才会对答案造成贡献,则可以变形为 ( ∏ i = 1 n p n x n , ∏ i = 1 n p n y n ) = = 1 (\prod_{i=1}^np_n^{x_n},\prod_{i=1}^np_n^{y_n})==1 (i=1npnxn,i=1npnyn)==1

所以 d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[(x,y)==1] d(ij)=xiyj[(x,y)==1]

(以上证明摘自:传送门)

证毕

现在就有了 A n s = ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = = 1 ] Ans=\sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}^{}\sum_{y|j}^{}[(x,y)==1] Ans=i=1Nj=1Mxiyj[(x,y)==1]

根据数论中切换枚举次序的套路以及莫比乌斯反演对布尔条件框的替换,我们得到
A n s = ∑ x = 1 N ∑ y = 1 M ⌊ N x ⌋ ⌊ M y ⌋ [ ( x , y ) = = 1 ] = ∑ x = 1 N ∑ y = 1 M ⌊ N x ⌋ ⌊ M y ⌋ ∑ k ∣ ( x , y ) μ ( k ) = ∑ k = 1 m i n ( N , M ) μ ( k ) ∑ k ∣ x ⌊ N x ⌋ ∑ k ∣ y ⌊ M y ⌋ = ∑ k = 1 m i n ( N , M ) μ ( k ) ∑ x = 1 ⌊ N k ⌋ ⌊ N k x ⌋ ∑ y = 1 ⌊ M k ⌋ ⌊ M k y ⌋ Ans=\sum_{x=1}^{N}\sum_{y=1}^{M}⌊\frac{N}{x}⌋⌊\frac{M}{y}⌋[(x,y)==1]\newline =\sum_{x=1}^{N}\sum_{y=1}^{M}⌊\frac{N}{x}⌋⌊\frac{M}{y}⌋\sum_{k|(x,y)}\mu(k)\newline =\sum_{k=1}^{min(N,M)}\mu(k)\sum_{k|x}^{}⌊\frac{N}{x}⌋\sum_{k|y}^{}⌊\frac{M}{y}⌋\newline =\sum_{k=1}^{min(N,M)}\mu(k)\sum_{x=1}^{⌊\frac{N}{k}⌋}⌊\frac{N}{kx}⌋\sum_{y=1}^{⌊\frac{M}{k}⌋}⌊\frac{M}{ky}⌋ Ans=x=1Ny=1MxNyM[(x,y)==1]=x=1Ny=1MxNyMk(x,y)μ(k)=k=1min(N,M)μ(k)kxxNkyyM=k=1min(N,M)μ(k)x=1kNkxNy=1kMkyM

于是这里使用分块优化,预处理 μ \mu μ的前缀和

最后考虑后面的两个Sigma怎么处理
可以观察发现它们都是 ∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^{n}⌊\frac{n}{i}⌋ i=1nin的形式,此处可以用分块优化 Θ ( n n ) \Theta(n\sqrt{n}) Θ(nn )预处理

其实还可以 Θ ( n ) \Theta(n) Θ(n)预处理,可以发现 ∑ i = 1 n ⌊ n i ⌋ = ∑ i = 1 n ∑ i ∣ d n 1 \sum_{i=1}^{n}⌊\frac{n}{i}⌋=\sum_{i=1}^{n}\sum_{i|d}^{n}1 i=1nin=i=1nidn1
显然是约数个数和 d ( n ) d(n) d(n)的前缀和函数,于是线性筛出 μ ( n ) \mu(n) μ(n) d ( n ) d(n) d(n),求出前缀和即可

每次询问 Θ ( n ) \Theta(\sqrt{n}) Θ(n ), 预处理 Θ ( n ) \Theta(n) Θ(n),总时间复杂度为 Θ ( n n ) \Theta(n\sqrt{n}) Θ(nn )

TIPS

线性筛约数个数时存一下最小的质数 p 1 p_1 p1的次方 + 1 +1 +1,即存下 ( k 1 + 1 ) (k_1+1) (k1+1)就可以方便的线性筛了

线性筛约数和同理,存一下最小的质数 p 1 p_1 p1所对应的首项为 1 1 1,公比为 p 1 p_1 p1,项数为 k 1 + 1 k_1+1 k1+1的等比数列,即存下 ∑ i = 1 k 1 p 1 i \sum_{i=1}^{k_1}p_1^i i=1k1p1i就可以愉快的线性筛了

AC code
#include 
#include 
#include 
using namespace std;

const int MAXN = 100001;
namespace Mobius
{
	#define LL long long
	int Prime[MAXN], Cnt, mu[MAXN], d[MAXN], Minseq[MAXN];
	bool IsnotPrime[MAXN];
	LL sum_MU[MAXN], sum_D[MAXN];
	void init()
	{
		mu[1] = d[1] = Minseq[1] = 1;
		for(int i = 2; i < MAXN; ++i)
		{
			if(!IsnotPrime[i])
				Prime[++Cnt] = i, mu[i] = -1, d[i] = Minseq[i] = 2;
			for(int j = 1; j <= Cnt && i * Prime[j] < MAXN; ++j)
			{
				IsnotPrime[i * Prime[j]] = 1;
				if(i % Prime[j] == 0)
				{
					Minseq[i * Prime[j]] = Minseq[i]+1;
					mu[i * Prime[j]] = 0;
					d[i * Prime[j]] = d[i] / Minseq[i] * Minseq[i * Prime[j]];
					break;
				}
				Minseq[i * Prime[j]] = 2;
				mu[i * Prime[j]] = -mu[i];
				d[i * Prime[j]] = d[i]<<1;
			}
		}
		for(int i = 1; i < MAXN; ++i)
			sum_MU[i] = sum_MU[i-1] + mu[i],
			sum_D[i] = sum_D[i-1] + d[i];
	}
	LL calc(int N, int M)
	{
		if(N > M) swap(N, M);
		LL ret = 0;
		for(int i = 1, j; i <= N; i=j+1)
		{
			j = min(N/(N/i), M/(M/i));
			ret += (sum_MU[j]-sum_MU[i-1]) * sum_D[N/i] * sum_D[M/i];
		}
		return ret;
	}
}
using namespace Mobius;
int main ()
{
	init();
	int T, n, m;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d%d", &n, &m);
		printf("%lld\n", calc(n, m));
	}
}

你可能感兴趣的:(莫比乌斯反演)