[NOI2010]能量采集

v.[NOI2010]能量采集

真正自己做出来的第一道莫反题祭~~~~

题意:

\(\sum_{i=1}^n\sum_{j=1}^m(2\gcd(i,j)-1)\)

开始推式子:

\(\begin{aligned}\sum_{i=1}^n\sum_{j=1}^m(2\gcd(i,j)-1) & =2\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)-nm\\ & =2\sum_{d=1}^{\min(n,m)}\sum_{i=1}^n\sum_{j=1}^md[\gcd(i,j)=d]-nm\\ & =2\sum_{d=1}^{\min(n,m)}d\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=d]-nm\\ & =2\sum_{d=1}^{\min(n,m)}d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}[\gcd(i,j)=1]-nm\\ & =2\sum_{d=1}^{\min(n,m)}d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\sum_{x|\gcd(i,j)}\mu(x)-nm\\ & =2\sum_{d=1}^{\min(n,m)}d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\sum_{x|i,x|j}\mu(x)-nm\\ & =2\sum_{d=1}^{\min(n,m)}d\sum_{x=1}^{\min(n/d,m/d)}\sum_{i=1}^{n/(dx)}\sum_{j=1}^{m/(dx)}\mu(x)-nm\\ & =2\sum_{d=1}^{\min(n,m)}d\sum_{x=1}^{\min(n/d,m/d)}\mu(x)\sum_{i=1}^{n/(dx)}\sum_{j=1}^{m/(dx)}1-nm\\ & =2\sum_{d=1}^{\min(n,m)}d\sum_{x=1}^{\min(n/d,m/d)}\mu(x)\left\lfloor\dfrac{n}{dx}\right\rfloor\left\lfloor\dfrac{m}{dx}\right\rfloor -nm\end{aligned}\)

到这里为止,就已经可以做了。

复杂度为(设\(n\)\(m\)同级)\(O(\sum_{i=1}^n\sqrt{\dfrac{n}{i}})\approx O(n)\)

但实际上还有\(O(\sqrt{n})\)的做法(虽然预处理是\(O(n)\)的):

\(2\sum_{d=1}^{\min(n,m)}d\sum_{x=1}^{\min(n/d,m/d)}\mu(x)\left\lfloor\dfrac{n}{dx}\right\rfloor\left\lfloor\dfrac{m}{dx}\right\rfloor -nm\)

\(T=dx\),则

\(\begin{aligned}\text{原式} & =2\sum_{T=1}^{\min(n,m)}\left\lfloor\dfrac{n}{T}\right\rfloor\left\lfloor\dfrac{m}{T}\right\rfloor\sum_{d|T}d\mu(\dfrac{T}{d})-mn\end{aligned}\)

这东西不还是\(O(n)\)的吗?

我们看一下后面的东西:\(\sum_{d|T}d\mu(\dfrac{T}{d})\)

我们规定一个函数\(id(x)=x\),则这个东西\(=\sum_{d|T}id(d)\mu(\dfrac{T}{d})\)

这个运算,有一个具体的名字,叫做狄利克雷卷积。它是这样的运算:

\(\boxed{h(n)=(f*g)(n)\Leftrightarrow h(n)=\sum_{d|T}f(d)*g(\dfrac{T}{d})}\)

这个运算,满足:

\(\boxed{\begin{cases}\text{1.交换律:}f*g=g*f\\\text{2.结合律:}(f*g)*h=f*(g*h)\\\text{3.分配律:}h*(f+g)=h*f+h*g\end{cases}}\)

它的更多性质我们将在接下来一一提到。不过,在这道题中它最大的作用是帮助我们将上面的东西转成狄利克雷卷积的形式,即

\(\begin{aligned}\text{原式} & =2\sum_{T=1}^{\min(n,m)}\left\lfloor\dfrac{n}{T}\right\rfloor\left\lfloor\dfrac{m}{T}\right\rfloor((id*\mu)(T))-mn\end{aligned}\)

好好好,我们搞出了一个新的运算。但是这有什么用吗?

\(\boxed{\text{如果}f\text{和}g\text{都是积性函数,那么}f*g\text{也是积性函数。}}\)

是积性函数就意味着我们可以用欧拉筛去筛它!

而我们已经知道了\(\mu\)函数是积性函数。用脑子稍微想想也知道,\(id\)函数肯定是积性函数。

这意味着,\(id*\mu\)也是一个积性函数,可以用欧拉筛。

而这个东西前一半的东西可以整除分块

那么我们就丧心病狂地把这个东西优化到了\(O(\sqrt{n})\)

尽管预处理还是\(O(n)\)的,但是已经很优秀了。感觉可以出成一道很毒瘤的题

先给出普通的\(O(n)\)的代码,而\(O(\sqrt{n})\)的我们将在下一题中用到:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,mu[100100],pri[100100],res;
void getmu(int N){
	mu[1]=1;
	for(int i=2;i<=N;i++){
		if(!pri[i])pri[++pri[0]]=i,mu[i]=-1;
		for(int j=1;j<=pri[0]&&i*pri[j]<=N;j++){
			pri[i*pri[j]]=true;
			if(!(i%pri[j]))break;
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=1;i<=N;i++)mu[i]+=mu[i-1]; 
}
signed main(){
	scanf("%lld%lld",&n,&m),getmu(min(n,m));
	for(int i=1;i<=min(n,m);i++){
		int x=n/i,y=m/i,lim=min(x,y),sum=0;
		for(int l=1,r;l<=lim;l=r+1)r=min(x/(x/l),y/(y/l)),sum+=(x/l)*(y/l)*(mu[r]-mu[l-1]);
		res+=2*i*sum;
	}
	res-=n*m;
	printf("%lld\n",res);
	return 0;
}

posted @ 2021-04-05 21:14  Troverld  阅读(42)  评论(0编辑  收藏  举报