莫比乌斯反演入门

来源:互联网 发布:淘宝店铺整体托管 编辑:程序博客网 时间:2024/05/21 08:48

首先

我们来了解一下什么是莫比乌斯反演……

假设有两个函数f(i),g(i),并且f(N)=i|Ng(i)
也就是

  • f(1)=g(1)
  • f(2)=g(1)+g(2)
  • f(3)=g(1)+g(3)
  • f(4)=g(1)+g(2)+g(4)
  • f(5)=g(1)+g(5)
  • f(6)=g(1)+g(2)+g(3)+g(6)
    .
    .
    .

g(i)f的关系??
列一下

  • g(1)=f(1)
  • g(2)=f(1)+f(2)
  • g(3)=f(1)+f(3)
  • g(4)=f(2)+f(4)
  • g(5)=f(1)+f(5)
  • g(6)=f(1)f(2)f(3)+f(6)
    .
    .
    .

???
继续列下去(本人过于懒惰
似乎g(N)=i|Nf(i)×??
而且,这个??i没有关系,而是和Ni有关系

我们暂且将这个函数设为μ(Ni)

并且这个函数的取值只有1,0,1

光这么看很难发现这个函数的规律,然而我们的大数学家莫比乌斯发现了(不然怎么叫莫比乌斯反演)
式子是这样的

μ(N)=1(1)m0N=1N=P1P2P3PmN=Pk11Pk22Pk33Pkmm,k1+k2+k3++km>m

P是互不相等的质数,k>0

第二条就是至少有一个k2

所以我们就有g(N)=i|Nf(i)μ(Ni)

这条式子也可以这么写g(N)=i|Nf(Ni)μ(i)

这个函数就是莫比乌斯函数

证明?

首先,莫比乌斯函数有几个性质。

  • 性质一
    d|nμ(d)=0|nN,n>1

    d|nμ(d)=1|n=1
  • 性质二 莫比乌斯函数是积性函数
    gcd(p,q)=1,μ(p)μ(q)=μ(pq)

先证性质一。
n=1时显然。

n>1
n=Pk11Pk22Pk33Pkmmd有其中一部分。
显然d的每个质因子指数为1才有贡献,否则μ(d)=0

那么设d中有r个质因子。
μ(d)=(1)r,这样的dCrm
所以

d|nμ(d)=r=0m(1)rCrm

我们有二项式定理

r=0m(1)rCrm=r=0mCrm(1)r1mr=(1+1)m=0

得证!

性质二似乎比较显然,此处不准备证明。
然后我们来证明反演。

f(N)=d|Ng(d)g(N)=d|Nf(nd)μ(d)=d|Nμ(d)i|Ndg(i)

然后我们运用一种叫交换主体的等价变换,就是将后面的f(i)移到前面来,这个似乎只能靠感觉,多练练就熟了。
下面直接是交换后的,想想为什么?

=i|Ng(i)d|Niμ(d)

不急,因为我们有性质一
i=N
g(N)1

i<N
i|Ng(i)0

综上
g(N)=i|Ng(i)d|Niμ(d)=g(N)得证!

应用

然而莫比乌斯函数怎么求?
可以用线性筛法!

void getprime(int lim){    int i,j,num=0;    fo(i,2,lim)     {        if (!bz[i])         {            prime[++num]=i;            mu[i]=-1;//质数就是一个质因子        }         for(j=1;i*prime[j]<=lim&&j<=num;j++)        {            bz[i*prime[j]]=1;            if (prime[j]==i) break;            if (!(i%prime[j]))             {                mu[i*prime[j]]=0; //显然prime[j]在i*prime[j]中指数大于等于2                break;            }             mu[i*prime[j]]=-mu[i];//多加了一个质因子乘上-1        }     }}

事实上,莫比乌斯反演还有个变形

f(k)=i=1nkg(ik)

g(k)=i=1nkf(ik)μ(i)

证明类似上面的证法,此处不再赘述。若有兴趣着可以参考度娘。

它可以非常好的应用在一些问题,比如说

f(N)不好求,但是i|Nf(i)好求,可以设为g(N)再用莫比乌斯反演解决。

例题([HAOI2011][BZOJ2301]Problem b)

对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。

我们有这个
g(k)表示1xN,1yM,gcd(x,y)=k(x,y)对数

f(k)表示1xN,1yM,k|gcd(x,y)(x,y)对数

那么显然有f(k)=i=1nkg(ik)(此处我们假设NM

f(k)非常好求,设x=kx1,y=ky1,那么只需要1x1Nk,1y1Mk

f(k)=NkMk 然后再使用莫比乌斯反演求解

这里可能会超时,所以对于NkMk,可能有很多一部分是相等的,可以用分块解决,单次询问的复杂度就变成了O(N+M)
附代码

#include<cstdio>#include<cstdlib>#include<algorithm>#include<iostream>#include<cstring>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;long long mu[50005];int a,b,c,d,k;int prime[50005],n;bool bz[50005];void getprime(int lim){    int i,j,num=0;    fo(i,2,lim)     {        if (!bz[i])         {            prime[++num]=i;            mu[i]=-1;        }         for(j=1;i*prime[j]<=lim&&j<=num;j++)        {            if (i*prime[j]>50000) break;            bz[i*prime[j]]=1;            if (prime[j]==i) break;            if (!(i%prime[j]))             {                mu[i*prime[j]]=0;                 break;            }             mu[i*prime[j]]=-mu[i];        }     }}int find(int k,int mx,int my){     int i=1,j;     long long ans=0;     while(i<=trunc(min(mx,my)/k))     {         j=min(mx/(mx/i),my/(my/i));         ans+=trunc(my/(i*k))*trunc(mx/(i*k))*(mu[j]-mu[i-1]);        i=j+1;     }     return (int)ans;  }int main(){    freopen("inversion.in","r",stdin);    getprime(50000);    scanf("%d",&n);    mu[1]=1;    int i;    fo(i,2,50000) mu[i]+=mu[i-1];    while(n-->0)     {        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);        printf("%d\n",(int)(find(k,b,d)-find(k,a-1,d)-find(k,b,c-1)+find(k,a-1,c-1)));    }}
0 0