[BZOJ2154][洛谷P1829]Crash的数字表格(莫比乌斯反演+基础应用:消gcd)

题面

https://www.luogu.com.cn/problem/P1829

题解

前置知识

要求\({\sum_{i=1}^{n}}{\sum_{j=1}^{m}}[i,j]\)

首先转化成为\({\sum_{i=1}^{n}}{\sum_{j=1}^{m}}{\frac{ij}{(i,j)}}\)

求和中化解gcd的小技巧

假设我们遇到求和\({\sum_{i=1}^{n}}{\sum_{j=1}^{m}}f((i,j))\),其中f是某给定函数。

那么我们可以设函数\(g = f {\times} {\mu}\),则由莫比乌斯反演,有\(f=g{\times}I\)。(此处及以下“\({\times}\)”表示狄利克雷卷积)然后做如下转化:

\[{\sum_{i=1}^{n}}{\sum_{j=1}^{m}}f((i,j)) \]

\[={\sum_{i=1}^{n}}{\sum_{j=1}^{m}}{\sum_{d|(i,j)}}g(d) \]

由于有\(d|(i,j)\)等价于\(d|i\)\(d|j\)的性质,可以进一步化简为:

\[={\sum_{i=1}^{n}}{\sum_{j=1}^{m}}{\sum_{d|i,d|j}}g(d) \]

\[={\sum_d}g(d){\sum_{i=1}^{n}}{\sum_{j=1}^{m}}[d|i][d|j] \]

\[={\sum_d}g(d)({\sum_{i=1}^{n}}[d|i])({\sum_{j=1}^{m}}[d|j]) \]

\[={\sum_d}g(d){{\lfloor}{\frac{n}{d}}{\rfloor}}{\lfloor}{\frac{m}{d}}{\rfloor} \]

即完成了gcd的化简。

如果求和是\({\sum_{i=1}^{n}}{\sum_{j=1}^{m}}g(i)h(j)f((i,j))\),过程也如出一辙,只要

\[g(d)+g(2d)+…+g({\lfloor}{\frac{n}{d}}{\rfloor}d) \]

\[h(d)+h(2d)+…+h({\lfloor}{\frac{m}{d}}{\rfloor}d) \]

能够快速处理,也能够适用此方法。

回本题。此题中\(f(x) = {\frac{1}{x}}\)

\[{\sum_{i=1}^{n}}{\sum_{j=1}^{m}}ijf((i,j)) \]

\[={\sum_{i=1}^{n}}{\sum_{j=1}^{m}}ij{\sum_{d|(i,j)}}g(d) \]

\[={\sum_{i=1}^{n}}{\sum_{j=1}^{m}}ij{\sum_{d|i,d|j}}g(d) \]

\[={\sum_{d}}g(d){\sum_{i=1}^{n}}{\sum_{j=1}^{m}}[d|i][d|j]ij \]

\[={\sum_{d}}g(d)({\sum_{i=1}^{n}}[d|i]i)({\sum_{j=1}^{n}}[d|j]j) \]

注意到两个括号内分别是

\[d+2d+…+{\lfloor}{\frac{n}{d}}{\rfloor}d \]

\[d+2d+…+{\lfloor}{\frac{m}{d}}{\rfloor}d \]

这两个等差数列之和,于是原式=

\[{\sum_d}g(d)d^2({\frac{1}{2}}{\lfloor}{\frac{n}{d}}{\rfloor}({\lfloor}{\frac{n}{d}}{\rfloor}+1))({\frac{1}{2}}{\lfloor}{\frac{m}{d}}{\rfloor}({\lfloor}{\frac{m}{d}}{\rfloor}+1)) \]

其中

\[g(d)={\sum_{p|d}}f({\frac{d}{p}}){\mu}(p) \]

\[={\sum_{p|d}}{\frac{p}{d}}{\mu(p)} \]

为了避免出现小数或者分数,简化计算,我们令\(h(d)=d*g(d)\)

那么有

\[h(d)={\sum_{p|d}}p{\mu(p)} \]

这是一个积性函数,可以线性求出。同时有原式=

\[{\sum_d}h(d)d({\frac{1}{2}}{\lfloor}{\frac{n}{d}}{\rfloor}({\lfloor}{\frac{n}{d}}{\rfloor}+1))({\frac{1}{2}}{\lfloor}{\frac{m}{d}}{\rfloor}({\lfloor}{\frac{m}{d}}{\rfloor}+1)) \]

可以枚举d,O(min(n,m))求解。

代码

#include<bits/stdc++.h>

using namespace std;

#define N 10000000
#define rg register
#define mod 20101009
#define F(x) (1ll*x*(x+1)/2%mod)

namespace ModCalc{
	inline void Inc(int &x,int y){
		x += y;if(x > mod)x -= mod; 
	}
	
	inline void Dec(int &x,int y){
		x -= y;if(x < 0)x += mod;
	}
	
	inline void Tms(int &x,int y){
		x = 1ll * x * y % mod;
	}
	
	inline int Add(int x,int y){
		Inc(x,y);return x;
	}
	
	inline int Sub(int x,int y){
		Dec(x,y);return x;
	}
	
	inline int Mul(int x,int y){
		Tms(x,y);return x;
	}
}
using namespace ModCalc;

int pn;
int pri[1200000+5];
bool isp[N+5];
int h[N+5];
int P[N+5]; //P[i]表示i的素因数分解式中底数最小的那一项的大小 

inline void Eular(){ //线性筛h[]
	pn = 0;
	h[1] = 1;
	for(rg int i = 2;i <= N;i++)isp[i] = 1;
	for(rg int i = 2;i <= N;i++){
		if(isp[i]){
			pri[++pn] = i;
			P[i] = i;
			h[i] = mod + 1 - i;
		} 
		for(rg int j = 1;i * pri[j] <= N;j++){
			isp[i*pri[j]] = 0;
			if(i % pri[j]){
				P[i*pri[j]] = pri[j];
				h[i*pri[j]] = Mul(h[i],h[pri[j]]);
			}	
			else{
				int I = i * pri[j];
				P[I] = Mul(P[i],pri[j]);
				if(P[I] == I)h[I] = h[i];
				else h[I] = Mul(h[I/P[I]],h[P[I]]); 
				break;
			} 
		}
	}
}

int n,m;

int main(){
	Eular();
	scanf("%d%d",&n,&m);
	int ans = 0;
	int M = min(n,m);
	for(rg int d = 1;d <= M;d++)Inc(ans,1ll*h[d]*d%mod*F(n/d)%mod*F(m/d)%mod);
	cout << ans << endl;
	return 0;
}
posted @ 2020-02-06 13:15  coder66  阅读(222)  评论(0编辑  收藏  举报