莫比乌斯反演——从入门到入土

莫比乌斯反演

前置芝士

整除分块 洛谷 P2261

清醒的头脑

对于 \(\varphi\)\(\mu\) 函数的认识

关键公式

\(\displaystyle\sum_{d|n}^{}\varphi(d)=n\)

\(\displaystyle\sum_{d|n}^{}\mu(d)=[n=1]\)

应用

下面,对于一道简单的题目进行分析。

传送门

洛谷P2257 YY的GCD

题目就是要求解

\(\qquad \qquad \qquad \qquad \qquad \qquad \displaystyle\sum_{i=1}^{N}{\sum_{j=1}^{M}{\sum_{p \in Prime}{[\gcd(i,j)=p]}}}\)

\(\min(N,M)=N\)

套路将枚举p的移到前面

\(= \displaystyle\sum_{p \in Prime}\sum_{i=1}^{N}{\sum_{j=1}^{M}{{[\gcd(i,j)=p]}}}\)

\(= \displaystyle\sum_{p \in Prime}\sum_{i=1}^{\lfloor \frac{N}{p} \rfloor}{\sum_{j=1}^{\lfloor \frac{M}{p} \rfloor}{{[\gcd(i,j)=1]}}}\)

看到了后面有套路公式,直接扔过去

\(= \displaystyle\sum_{p \in Prime}\sum_{i=1}^{\lfloor \frac{N}{p} \rfloor}{\sum_{j=1}^{\lfloor \frac{M}{p} \rfloor}{{\sum_{d|i \And d|j}{\mu(d)}}}}\)

套路枚举d

\(= \displaystyle\sum_{p \in Prime}\sum_{1 \leq d \leq N}{\mu(d)}\sum_{i=1}^{\lfloor \frac{N}{p} \rfloor}{\sum_{j=1}^{\lfloor \frac{M}{p} \rfloor}{{[d|i]*[d|j]}}}\)

观察到后面那个其实就是枚举在 \(i,j\) 合适的范围之内找到d的倍数,显然可以化解成下面的形式

\(= \displaystyle\sum_{p \in Prime}\sum_{1 \leq d \leq N}{\mu(d)}\lfloor \frac{N}{dp} \rfloor \lfloor \frac{M}{dp} \rfloor\)

其实推式子到这一步已经结束了,但是呢,明显,这个式子明显大于 \(\mathbf{O}(N)\) 所以要进一步优化,笔者到这里也想不到下一步优化了,不过确实非常巧妙

\(T = dp\)

显然有 \(d|T\quad p|T\) ,并且 \(T \leq N\) ,且原式可以换成如下形式

\(= \displaystyle\sum_{p \in Prime}\sum_{1 \leq d \leq N}{\mu(d)}\lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor\)

这边枚举一手 p 和 T

\(= \displaystyle\sum_{p \in Prime}\sum_{1 \leq T \leq N,q|T}{\mu(\frac{T}{p})}\lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor\)

\(= \displaystyle\sum_{1 \leq T \leq n}\sum_{p \in Prime,q|T}{\mu(\frac{T}{p})}\lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor\)

\(= \displaystyle\sum_{1 \leq T \leq n}\lfloor \frac{N}{T} \rfloor \lfloor \frac{M}{T} \rfloor\sum_{p \in Prime,q|T}{\mu(\frac{T}{p})}\)

很舒服,发现前面可以整除分块,但是后面呢? 单独拿出来康康

\(\qquad \qquad \displaystyle\sum_{p \in Prime,q|T}{\mu(\frac{T}{p})}\)

因为在循环中,我们的嵌套循环中的第二个循环明显可以把 \(T\) 看成是一个常数,所以说 用中文说出这个和式的含义

要求 \(T\) 除以 \(T\) 的所有质因数的 \(\mu\)

说到这里,预处理已经十分明显了。

#include <bits/stdc++.h>
#define debug puts("I ak IOI several times");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
    t=0; register char ch=getchar(); register int fflag=1;
    while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
    while(('0'<=ch&&ch<='9')){t=((t<<1)+(t<<3))+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){
    read(t);read(args...);
}
template <typename T>inline void write(T x){
    if(x<0) putchar('-'),x=~(x-1); int s[40],top=0;
    while(x) s[++top]=x%10,x/=10; if(!top) s[++top]=0;
    while(top) putchar(s[top--]+'0');
}
int n,T,m;
bool notprime[10000008];
int miu[10000008],c[10000008],sum[10000008];
int prime[5000008],cnt;
void Shai(int K){
	notprime[1]=1; miu[1]=1;
	for(int i=2;i<=K;++i){
		if(!notprime[i]){
			prime[++cnt]=i;
			miu[i]=-1;
		}
		for(int j=1;j<=cnt;++j){
			int t=prime[j]*i;
			if(t>K) break;
			notprime[t]=1;
			if(i%prime[j]==0) break;
			miu[t]=-miu[i];
		}
	}
	for(int i=1;i<=cnt;++i)
		for(int j=1;j*prime[i]<=K;++j)
			c[prime[i]*j]+=miu[j];
	for(int i=1;i<=K;++i) sum[i]=sum[i-1]+c[i];
}
int main(){
	read(T);
	Shai(10000005);
	while(T--){
		read(n,m);
		if(n>m) swap(n,m);
		long long ans=0;
		long long l,r;
		l=r=1;
		//for(int dp=1;dp<=n;++dp) ans+=(n/dp)*(m/dp)*c[dp];
		for(;r<=n&&l<=n;l=r+1){
			long long nowans=(n/l)*(m/l);
			r=min(n/(n/l),m/(m/l));
			ans+=nowans*(long long)(sum[r]-sum[l-1]);
		}
		cout<<ans<<endl;
	}
    return 0;
}
//Welcome back,Chtholly.
posted @ 2021-12-02 20:03  Mercury_City  阅读(35)  评论(0编辑  收藏  举报