P1829 [国家集训队]Crash的数字表格 / JZPTAB 题解

这篇博客介绍了如何解决一道关于计算数字表格中元素最小公倍数之和的数学问题。通过推导公式,将问题简化为计算因数和与 Mobius 函数的组合,并利用积性函数的性质,采用线性筛预处理方法,实现O(n)的时间复杂度解决方案。

博客园同步

原题链接

简要题意:

∑ i = 1 n ∑ j = 1 m lcm ⁡ ( i , j ) \sum_{i=1}^n \sum_{j=1}^m \operatorname{lcm}(i,j) i=1nj=1mlcm(i,j)

一言不合就推式子。

∑ i = 1 n ∑ j = 1 m lcm ⁡ ( i , j ) \sum_{i=1}^n \sum_{j=1}^m \operatorname{lcm}(i,j) i=1nj=1mlcm(i,j)

= ∑ i = 1 n ∑ j = 1 m i j gcd ⁡ ( i , j ) = \sum_{i=1}^n \sum_{j=1}^m \frac{ij}{\gcd(i,j)} =i=1nj=1mgcd(i,j)ij

= ∑ d = 1 min ⁡ ( n , m ) 1 d ∑ i = 1 m ∑ j = 1 n i j [ gcd ⁡ ( i , j ) = = d ] = \sum_{d=1}^{\min(n,m)} \frac{1}{d} \sum_{i=1}^m \sum_{j=1}^n ij [\gcd(i,j)==d] =d=1min(n,m)d1i=1mj=1nij[gcd(i,j)==d]

= ∑ d = 1 min ⁡ ( n , m ) 1 d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j d 2 [ gcd ⁡ ( i , j ) = = 1 ] = \sum_{d=1}^{\min(n,m)} \frac{1}{d} \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor} ijd^2 [\gcd(i,j)==1] =d=1min(n,m)d1i=1dnj=1dmijd2[gcd(i,j)==1]

= ∑ d = 1 min ⁡ ( n , m ) d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ [ gcd ⁡ ( i , j ) = = 1 ] = \sum_{d=1}^{\min(n,m)} d \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor} [\gcd(i,j)==1] =d=1min(n,m)di=1dnj=1dm[gcd(i,j)==1]

= ∑ d = 1 min ⁡ ( n , m ) d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j ∑ x ∣ gcd ⁡ ( i , j ) μ x = \sum_{d=1}^{\min(n,m)} d \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor} ij \sum_{x | \gcd(i,j)} \mu_x =d=1min(n,m)di=1dnj=1dmijxgcd(i,j)μx

= ∑ d = 1 min ⁡ ( n , m ) d ∑ x = 1 min ⁡ ( ⌊ n d ⌋ , ⌊ m d ⌋ ) x 2 μ x s ⌊ n d x ⌋ s ⌊ m d x ⌋ = \sum_{d=1}^{\min(n,m)} d \sum_{x=1}^{\min(\lfloor \frac{n}{d} \rfloor,\lfloor \frac{m}{d} \rfloor)} x^2 \mu_x s_{\lfloor \frac{n}{dx} \rfloor} s_{\lfloor \frac{m}{dx} \rfloor} =d=1min(n,m)dx=1min(dn,dm)x2μxsdxnsdxm

其中

s x = ∑ i = 1 x i = x × ( x + 1 ) 2 s_x = \sum_{i=1}^x i = \frac{x \times (x+1)}{2} sx=i=1xi=2x×(x+1)

回到原式:

= ∑ T = 1 n s ⌊ n T ⌋ s ⌊ m T ⌋ ( T ∑ d ∣ T d μ T ) = \sum_{T=1}^n s_{\lfloor \frac{n}{T} \rfloor} s_{\lfloor \frac{m}{T} \rfloor} \big(T \sum_{d|T} d \mu_T \big) =T=1nsTnsTm(TdTdμT)

括号内的东西我们预处理,括号外面的直接 整除分块。(实际上没有这个必要了)

那么如何预处理呢?单独搞出这个式子。

T ∑ d ∣ T d μ T T \sum_{d|T} d \mu_T TdTdμT

T μ T ∑ d ∣ T d T \mu_T \sum_{d|T} d TμTdTd

咦?是不是很熟悉? T μ T T \mu_T TμT 我们直接预处理就可以了。考虑,令:

f i = ∑ d ∣ i d f_i = \sum_{d|i} d fi=did

(其实 f i f_i fi 就是 i i i 的因数之和)

那么可得:

f i × j = f i × f j ( [ gcd ⁡ ( i , j ) ] = = 1 ) f_{i \times j} = f_i \times f_j \big([\gcd(i,j)]==1 \big) fi×j=fi×fj([gcd(i,j)]==1)

f f f积性函数

所以用线性筛预处理即可。

时间复杂度: O ( n ) O(n) O(n).

实际得分: 100 p t s 100pts 100pts.

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e7+1;
const ll MOD=20101009;

inline int read(){char ch=getchar(); int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}

int prime[N],mu[N],n,m;
int cnt=0; bool h[N];
ll ans=0;

inline void Euler(int n) {
	mu[1]=1; for(register int i=2;i<=n;i++) {
		if(!h[i]) mu[i]=MOD-i+1,prime[++cnt]=i;
		for(register int j=1;j<=cnt && i*prime[j]<=n;j++) {
			h[i*prime[j]]=1;
			if(i%prime[j]==0) {mu[i*prime[j]]=mu[i];break;}
			mu[i*prime[j]]=(1ll*mu[i]*mu[prime[j]])%MOD;
		}
	} for(register int i=1;i<=n;i++) mu[i]=1ll*mu[i]*i%MOD;
	for(register int i=1;i<=n;i++) mu[i]=(mu[i]+mu[i-1])%MOD;
} //欧拉筛预处理

inline ll Sieve(ll n) {return (n*(n+1)>>1)%MOD;} //求 s

int main() {
	Euler(N-1);
	n=read(),m=read();
	if(n>m) swap(n,m);
	for(int l=1;l<=n;) {
		int r=min(n/(n/l),m/(m/l));
		ans=(ans+1ll*(mu[r]-mu[l-1]+MOD)*Sieve(n/l)%MOD*Sieve(m/l)%MOD)%MOD;
		l=r+1; //整除分块
	} printf("%lld\n",ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值