<学习笔记> 莫比乌斯反演
\(f(n)\) 和 \(g(n)\) 是定义在整数集上的两个函数,满足一下关系:
但是手摸发现不仅可以从 \(g \rightarrow f\),还可以 \(f \rightarrow g\),发现还满足这个关系:
\(\mu(x) = \begin{cases}1 \qquad x=1 \\ 0 \qquad 存在平方因子 \qquad \\ (-1)^k \qquad k为质因子个数\end{cases}\)
性质一: 对于任意的正整数 \(n\),有 \(\sum_{d \mid n} \mu(d)=\begin{cases}1 \qquad 若n=1 \\ 0 \qquad 若 n >1 \end{cases}\)
证明
当 \(n=1\) 时,\(\sum_{d \mid n} \mu(d)=1\),成立。
当 \(n>1\) 时,设 \(n=P_1^{x_1} ... p_k^{x_k}\) ,设 \(d= P_1^{y_1}... P_k^{y_k}\) 。因为 \(y_i > 2\) 全为 \(0\),我们只考虑 \(y_i\) 为 \(0/1\) 的情况,假设 \(d\) 中有 \(r\) 个 \(n\) 的互异质因子,且质因子质数位 \(1\) ,那么对应 $ \mu(d) = (-1)^r$,这样的 \(d\) 有 \(C^r_k\) 个,所以 \(\sum_{d \mid n} \mu(d) = \sum_{r=0}^k C^r_k * (-1)^r =(1-1)^k=0\),其实就是二项式定理。
性质二: \(\mu(n)\) 是积性函数。
证明
易证。莫比乌斯反演的证明
形式一
证明一
将上式换成以 \(g(i)\) 为主体的形式,那么有:
根据性质一,只有 \(i=n\) 时才有值,否则全为 \(0\)。
综上 \(=g(n)\) 得证。
证明二
设 \(I(n)=1\),\(id(n)=n\),\(\epsilon(n)=[n=1]\)
单位元 \(\epsilon\) 满足 \(f * \epsilon= f\)
根据狄利克雷卷积得到几个性质:
-
\(\mu * I =\epsilon\)
-
\(\varphi * I = id\)
-
\(\mu * id= \varphi\)
给出的条件等价于 \(g = f * I\)
根据性质一 \(g * \mu =f * I * \mu=f * \epsilon=f\),得证。
变形
证明
另 \(T=d*d_1\),则有上式
根据性质一有,只有当 \(T=1\) 时,原式为 \(g(i)\) , 得证。
莫比乌斯反演的性质
\(g(n)\) 是积性函数的充分必要条件是 \(f(n)\) 是积性函数。
莫比乌斯反演的应用
\(g(i)\) 很难求,但是 \(f(i)\) 很好求,可以根据反演求 \(g(i)\)。
P4449 于神之怒加强版
设 \(f(p)\) 表示 \(gcd(i,j)=p\) 的个数,那么 \(Ans=\sum_{p} f(p)*p^k\)。
发现 \(f(p)\) 不好求,那么我们设 \(g(p)\) 表示 \(p \mid gcd(i,j)\) 的个数,那么 \(g(p)= \lfloor \frac{n}{p} \rfloor \times \lfloor \frac{m}{p} \rfloor\)
那么
另 \(T=d*p\) 则有 $$Ans=\sum_{T=1}^{n} \lfloor \frac{n}{T} \rfloor * \lfloor \frac{m}{T} \rfloor \sum_{p \mid T} \mu(\frac{T}{p})*p^k$$
那么我们只需要线性求出 \(\sum_{p \mid T} \mu(\frac{T}{p})*p^k\) 就可以了。
另 \(g(x)=x*k\),设 \(G(T)=\sum_{p \mid T} \mu(\frac{T}{p})*g(p)\)。
首先可以知道 \(G(x)\) 为积性函数,所以 \(G(a*b) =G(a)*G(b) (gcd(a,b)=1)\)。
那么我们尝试证明 \(G(a*b) =G(a)*b^k (gcd(a,b) \neq 1)\)
我们设 \(a=p_1^{k_1} ···p_n^{k_n}\),另 \(b=p_t (t \leq n)\)。
因为有 \(G(a)=\prod_{i=1}^{n} G(p_i^{k_i})\)
那么就有
只有 \(i=0 /1\) 时才有值,那么有
那么
那么我们就可以在线性筛的时候求出,然后计算答案直接整数分块,复杂度 \(O(T \sqrt n)\)。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5*1e6+10;
const int mod=1e9+7;
int prime[N],nprime[N],mul[N],f[N],sumf[N];
int T,k;
int qpow(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
void get_prime(){
mul[1]=1;
f[1]=1;
for(int i=2;i<=N-10;i++){
if(!nprime[i]){
f[i]=(qpow(i,k)-1+mod)%mod;
prime[++prime[0]]=i;
mul[i]=-1;
}
for(int j=1;j<=prime[0] && i*prime[j]<=N-10;j++){
int tmp=i*prime[j];
nprime[tmp]=1;
mul[tmp]=mul[i]*mul[prime[j]];
if(i%prime[j]==0){
f[tmp]=f[i]*qpow(prime[j],k)%mod;
mul[tmp]=0;
break;
}
f[tmp]=(f[i]*f[prime[j]]%mod)%mod;
}
}
for(int i=1;i<=N-10;i++) sumf[i]=(sumf[i-1]+f[i])%mod;
}
signed main(){
scanf("%lld%lld",&T,&k);
get_prime();
while(T--){
int n,m;
scanf("%lld%lld",&n,&m);
if(n>m) swap(n,m);
int l=1,r=0;
int ans=0;
while(l<=n){
int ta=n/l,tb=m/l;
if(!ta||!tb) break;
r=min(n/ta,m/tb);
ans=(ans+ta*tb%mod*(sumf[r]-sumf[l-1]+mod)%mod)%mod;
l=r+1;
}
printf("%lld\n",ans);
}
}
DZY Loves Math
首先它让求 \(\sum_{i=1}^n \sum_{j=1}^m F(\gcd(i,j))\)
然后套路的转化为
另 \(T=xd\) ,则有
现在只需要求出 \(G(T)=\sum_{x \mid T} F(x) * \mu(\frac{T}{x})\) 就可以整除分块了。
我们设 \(T=p_1^{z_1} ... p_k^{z_k}\) , \(x=p_1^{y_1} ... p_k^{y_k}\)。
我们设 \(a\) 为最大的 \(z_i\), \(q\) 表示 \(z_i\) 为最大值的个数,\(k\) 为质因子个数。
我们考虑 \(\mu(\frac{T}{d}) \neq 0\),所以 \(y_i=z_i / z_i-1\) , 那么 \(F(x)=a /a-1\)。
当 \(q=k\) 时
- 若最大值为 \(F(d)=a\),那么只要满足一个为 \(z_i=y_i\),所以有 (补一位进行二项式定理)
- 若最大值为 \(F(d)=a-1\),就有
那么这部分答案为 \(g(T)=-a*(-1)^k+(a-1)*(-1)^k = (-1)^{k+1}\)。
当 \(q<k\) 时
这时不论 \(F(d)=a\) 还是 \(F(d)=a-1\),都需要考虑另外 \(k-q\) 个元素也就是在上式乘上个 \(\sum_{j=0}^{k-q}(-1)^jC^j_{k-q}\) 发现这部分为零,所以这部分的答案为 \(g(T)=0\)。
可以用线性筛来求,发现每个数会被最小的质数筛掉,那么我们维护一个 \(mnsum(x)\) 表示 \(x\) 的最小质因子个数, \(excp(x)\) 表示除了最小质因子之外的数,然后求得时候维护。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+10;
int g[N],mnsum[N],excp[N];
int prime[N];
bool nprime[N];
void get_prime(){
for(int i=2;i<=N-5;i++){
if(!nprime[i]){
prime[++prime[0]]=i;
g[i]=mnsum[i]=excp[i]=1;
}
for(int j=1;j<=prime[0] && i*prime[j]<=N-5;j++){
int k=prime[j]*i;
nprime[k]=1;
if(i%prime[j]==0){
excp[k]=excp[i];
mnsum[k]=mnsum[i]+1;
if(excp[k]==1) g[k]=1;
else g[k]=(mnsum[excp[k]]==mnsum[k]?-g[excp[k]]:0);
break;
}
excp[k]=i,mnsum[k]=1;
g[k]=(mnsum[i]==1?-g[i]:0);
}
}
for(int i=1;i<=N-5;i++) g[i]+=g[i-1];
}
signed main(){
get_prime();
int T;
scanf("%lld",&T);
while(T--){
int a,b;
scanf("%lld%lld",&a,&b);
if(a>b) swap(a,b);
int l=1,r=0;
int ans=0;
while(l<=a){
int ta=a/l,tb=b/l;
if(!ta || !tb) break;
int r=min(a/ta,b/tb);
ans+=ta*tb*(g[r]-g[l-1]);
l=r+1;
}
printf("%lld\n",ans);
}
}
[SDOI2015]约数个数和
首先给出结论 \(d(nm)=\sum_{i \mid n}^{j \mid m} [gcd(i,j)=1]\)
证明
设 \(nm=p_1^{a_1} ... p_k^{a_k}\),那么有 \(d(nm)=\prod_{i=1}^{k} a_i+1\)
设 \(n=p_1^{b_1} ... p_k^{b_k}\),\(m=p_1^{a_1-b_1} ... p_k^{a_k-b_k}\)
设 \(i=p_1^{x_1} ... p_k^{x_k}\),\(j=p_1^{y_1} ... p_k^{y_k}\)
要想 \(gcd(i,j)=1\),必须满足 \(x_i=0\) 或 \(y_i=0\)
-
当 \(x_1=0\) 时,那么 \(y_1\) 可以取 \([0,a_1-b_1]\)。
-
当 \(y_1=0\) 时,那么 \(x_1\) 可以取 \([0,b_1]\)。
那么对于第一个质因子,符合条件的组合就有 \(a_1-b_1+1+b_1+1-1=a_1+1\)。
以此类推,那么所有符合条件的组合就有 \(\prod_{i=1}^{i=k} a_i+1\)。
因此 \(\sum_{i \mid n}^{j \mid m} [gcd(i,j)=1] = \prod_{i=1}^{i=k} a_i+1 = d(nm)\)。
回归正题那么原式就为
设 \(f(x)=\sum_{x=1}^{n}\sum_{y=1}^{m} \lfloor \frac{n}{x} \rfloor \lfloor \frac{m}{y} \rfloor [gcd(x,y)=x]\)
设 \(g(x)=\sum_{x=1}^{n}\sum_{y=1}^{m} \lfloor \frac{n}{x} \rfloor \lfloor \frac{m}{y} \rfloor [x | gcd(x,y)]\)
因为 \(\lfloor \frac{n}{dx} \rfloor=\lfloor \frac{\lfloor \frac{n}{dx} \rfloor}{x} \rfloor\) ,设 \(s(n)=\sum_{i=1}^{n}\lfloor \frac{n}{i} \rfloor\),那么 \(g(d)=s(\frac{n}{d})s(\frac{m}{d})\)
根据莫比乌斯反演,就有
因为我们只需要求 $f(1),那么答案就是 \(f(1)=\sum_{d=1}^{n} g(d) *\mu(d)\)
整除分块就可以了。
code
// P3327 [SDOI2015] 约数个数和
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=50005;
int mul[N],suml[N];
int prime[N];
bool nprime[N];
void get_prime(){
mul[1]=1;
for(int i=2;i<=N-3;i++){
if(!nprime[i]){
prime[++prime[0]]=i;
mul[i]=-1;
}
for(int j=1;j<=prime[0] && i*prime[j]<=N-3;j++){
int k=prime[j]*i;
nprime[k]=1;
if(i%prime[j]==0){
mul[k]=0;
break;
}
mul[k]=mul[prime[j]]*mul[i];
}
}
for(int i=1;i<=N-3;i++){
suml[i]=suml[i-1]+mul[i];
}
}
int s[N];
signed main(){
get_prime();
int T;
scanf("%lld",&T);
for(int n=1;n<=N-3;n++){
int l=1,r=0;
while(l<=n){
int t=n/l;
if(!t) break;
int r=n/t;
s[n]+=(r-l+1)*t;
l=r+1;
}
}
while(T--){
int n,m;
scanf("%lld%lld",&n,&m);
if(n>m) swap(n,m);
int ans=0;
int l=1,r=0;
while(l<=n){
int ta=n/l,tb=m/l;
if(!ta || !tb) break;
int r=min(n/ta,m/tb);
ans+=s[ta]*s[tb]*(suml[r]-suml[l-1]);
l=r+1;
}
printf("%lld\n",ans);
}
}

浙公网安备 33010602011771号