BZOJ 2154 Crash的数字表格 莫比乌斯反演

n , m ≤ 1 e 7 n,m\leq1e7 n,m1e7,求 ∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum\limits_{i=1}^n\sum\limits_{j=1}^{m}lcm(i,j) i=1nj=1mlcm(i,j)
不妨设 n ≤ m n\leq m nm,则原式
= ∑ i = 1 n ∑ j = 1 m i ∗ j g c d ( i , j ) =\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\frac{i*j}{gcd(i,j)} =i=1nj=1mgcd(i,j)ij
= ∑ g = 1 n 1 g ∑ i = 1 n ∑ j = 1 m i j [ g c d ( i , j ) = g ] =\sum\limits_{g=1}^{n}\frac{1}{g}\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}ij[gcd(i,j)=g] =g=1ng1i=1nj=1mij[gcd(i,j)=g]
= ∑ g = 1 n g ∑ i = 1 n / g ∑ j = 1 m / g i j [ g c d ( i , j ) = 1 ] =\sum\limits_{g=1}^{n}g\sum\limits_{i=1}^{n/g}\sum\limits_{j=1}^{m/g}ij[gcd(i,j)=1] =g=1ngi=1n/gj=1m/gij[gcd(i,j)=1]
= ∑ g = 1 n g ∑ i = 1 n / g ∑ j = 1 m / g i j ∑ d ∣ g c d ( i , j ) μ ( d ) =\sum\limits_{g=1}^{n}g\sum\limits_{i=1}^{n/g}\sum\limits_{j=1}^{m/g}ij\sum\limits_{d|gcd(i,j)}\mu(d) =g=1ngi=1n/gj=1m/gijdgcd(i,j)μ(d)
= ∑ g = 1 n g ∑ d = 1 n / g μ ( d ) ∑ i = 1 n / g d ∑ j = 1 m / g d i j d 2 =\sum\limits_{g=1}^{n}g\sum\limits_{d=1}^{n/g}\mu(d)\sum\limits_{i=1}^{n/gd}\sum\limits_{j=1}^{m/gd}ijd^2 =g=1ngd=1n/gμ(d)i=1n/gdj=1m/gdijd2
= ∑ g = 1 n g ∑ d = 1 n / g μ ( d ) d 2 n g d ∗ ( n g d + 1 ) 2 ∗ m g d ∗ ( m g d + 1 ) 2 =\sum\limits_{g=1}^{n}g\sum\limits_{d=1}^{n/g}\mu(d)d^2\frac{\frac{n}{gd}*(\frac{n}{gd}+1)}{2}*\frac{\frac{m}{gd}*(\frac{m}{gd}+1)}{2} =g=1ngd=1n/gμ(d)d22gdn(gdn+1)2gdm(gdm+1)
μ ( d ) d 2 \mu(d)d^2 μ(d)d2可以线性时间预处理前缀和,两个分式 O ( 1 ) O(1) O(1)计算得到,对于内外两层各做一次分块。时间复杂度为 O ( n ∗ n ) = O ( n ) O(\sqrt n *\sqrt n)=O(n) O(n n )=O(n)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=1e7+7;
int pri[N],tot=0;
bool ok[N];
int mu[N];
ll sum[N];
ll n,m;
const int mod=20101009; 
void getmu() {
	mu[1]=1;
	for(int i=2;i<=n;i++) {
		if(!ok[i]) pri[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*pri[j]<=n;j++) {
			ok[i*pri[j]]=1;
			if(i%pri[j]) mu[i*pri[j]]=-mu[i];
			else { mu[i*pri[j]]=0;break; }
		}
	}
	sum[1]=mu[1];
	for(int i=2;i<=n;i++) {
		sum[i]=sum[i-1]+((1LL*i*i)%mod*mu[i])%mod;
		sum[i]%=mod;	
	}
} 
ll cal(ll x) { return (x*(x+1)>>1)%mod; }
ll sub(ll x,ll y) {
	if(x-y>=0) return x-y;
	else return x-y+mod; 
}
ll solve(ll n,ll m) {
	ll ans=0;
	for(int l=1,r=0;l<=n;l=r+1) {
		r=min(n/(n/l),m/(m/l));
		ans+=sub(sum[r],sum[l-1])*cal(n/l)%mod*cal(m/l)%mod; 
		ans%=mod;
	}
	return ans;
}
int main() { 
	scanf("%lld%lld",&n,&m);
	if(n>m) swap(n,m);
	getmu();  
	ll ans=0;
	for(int l=1,r=0;l<=n;l=r+1) {
		r=min(n/(n/l),m/(m/l));
		ans+=(1LL*(l+r)*(r-l+1)/2)%mod*solve(n/l,m/l)%mod;
		ans%=mod;
	}
	printf("%lld\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值