2019.01.19【NOI2010】【BZOJ2005】【洛谷1447】能量采集(莫比乌斯反演)

BZOJ传送门

洛谷传送门


解析:

当然这道题有常数十分优秀的容斥 O ( n log ⁡ n ) O(n\log n) O(nlogn)做法:https://blog.csdn.net/zxyoi_dreamer/article/details/82289575

以及复杂度十分优秀的 O ( n ) O(n) O(n)~ O ( n ) O(\sqrt n) O(n )做法。
(这个符号就是指 O ( n ) O(n) O(n))预处理, O ( n ) O(\sqrt n) O(n )回答每个询问

思路:

O ( n ) O(n) O(n)做法就是莫比乌斯反演,不过因为线性筛的较大常数被容斥做法吊打。

要不开一下 1 e 7 1e7 1e7?

首先将所有格子上的数+1可以发现格子上的数就是行和列的 g c d × 2 gcd\times 2 gcd×2

那么问题就是这个了: ∑ i = 1 n ∑ j = 1 m g c d ( i , j ) \sum_{i=1}^n\sum_{j=1}^mgcd(i,j) i=1nj=1mgcd(i,j)

莫比乌斯反演,首先大力推式子:

∑ d d ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] = ∑ d d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ [ g c d ( i , j ) = 1 ] = ∑ d d ( ∑ T = 1 ⌊ min ⁡ ( n , m ) d ⌋ ⌊ n d T ⌋ ⌊ m d T ⌋ μ ( T ) ) \begin{aligned} &\sum_{d}d\sum_{i=1}^{n}\sum_{j=1}^m[gcd(i,j)=d]\\ =&\sum_{d}d\sum_{i=1}^{\lfloor\frac{n}d\rfloor}\sum_{j=1}^{\lfloor\frac{m}d\rfloor}[gcd(i,j)=1]\\ =&\sum_{d}d(\sum_{T=1}^{\lfloor\frac{\min(n,m)}{d}\rfloor}\lfloor\frac{n}{dT}\rfloor\lfloor\frac{m}{dT}\rfloor\mu(T)) \end{aligned} ==ddi=1nj=1m[gcd(i,j)=d]ddi=1dnj=1dm[gcd(i,j)=1]dd(T=1dmin(n,m)dTndTmμ(T))

可以 O ( n n ) O(n\sqrt n) O(nn )回答每个询问了,AC此题已经没问题了。

但是我们的目标是 O ( n ) O(\sqrt n) O(n )回答每个询问,继续化简:

考虑改变枚举顺序,这次变动有点大,请读者仔细观察

A n s = ∑ t = 1 min ⁡ ( n , m ) ⌊ n t ⌋ ⌊ m t ⌋ ∑ D ∣ t μ ( D ) t D \begin{aligned} Ans=\sum_{t=1}^{\min(n,m)}\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}t\rfloor\sum_{D\mid t}\mu(D)\frac{t}D \end{aligned} Ans=t=1min(n,m)tntmDtμ(D)Dt

然后后面这个东西: ∑ D ∣ t μ ( D ) t D \sum_{D\mid t}\mu(D)\frac{t}{D} Dtμ(D)Dt,学过 D i r i c h l e t Dirichlet Dirichlet卷积的都知道, μ ∗ I d = ϕ \mu*Id=\phi μId=ϕ,所以这个就是个欧拉函数。

所以我们要求的东西 ∑ i = 1 n ∑ j = 1 m g c d ( i , j ) = ∑ t = 1 min ⁡ ( n , m ) ⌊ n t ⌋ ⌊ m t ⌋ ϕ ( t ) \sum_{i=1}^n\sum_{j=1}^mgcd(i,j)=\sum_{t=1}^{\min(n,m)}\lfloor\frac{n}t\rfloor\lfloor\frac{m}t\rfloor\phi(t) i=1nj=1mgcd(i,j)=t=1min(n,m)tntmϕ(t)

于是就可以整除分块了,维护一下 ϕ \phi ϕ的前缀和就行了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define cs const

cs int P=100005;
int prime[P],pcnt,phi[P];
bool mark[P];

inline void linear_sieves(int len=P-5){
	phi[1]=1;
	for(int re i=2;i<=len;++i){
		if(!mark[i])prime[++pcnt]=i,phi[i]=i-1;
		for(int re j=1;i*prime[j]<=len;++j){
			mark[i*prime[j]]=true;
			if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
			phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}

int n,m;
ll ans;
signed main(){
	linear_sieves();
	scanf("%d%d",&n,&m);
	for(int re i=1;i<=min(n,m);++i)ans+=(ll)(n/i)*(m/i)*phi[i];
	cout<<2*ans-(ll)m*n; 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值