zoukankan      html  css  js  c++  java
  • 浅谈算法——莫比乌斯反演

    前言

    莫比乌斯反演(又称懵逼钨丝繁衍),那种让人看了就懵逼的东西(其实是我太菜了)
    莫比乌斯反演在知道之后对解题十分有帮助,(O(n))的柿子分分钟化成(O(sqrt n))
    那么,什么是莫比乌斯反演呢?

    莫比乌斯反演

    1.莫比乌斯反演
    如果说,有(f(n))(g(n))是定义在正整数集合上的两个函数,并且满足

    [f(n)=sumlimits_{d|n} g(d) ]

    那么就有

    [g(n)=sumlimits_{d|n} f(dfrac{n}{d}) imes mu(d) ]

    这个变形也就是莫比乌斯反演

    2.莫比乌斯函数(性质/证明)
    对于任意整数n,满足

    [sumlimits_{d|n} mu(d)=egin{cases}1&,n=1\0&,n>1end{cases} ]

    证明:

    • n=1时显然
    • n>1时,设(n=P_1^{x_1} imes P_2^{x_2} imes ... imes P_k^{x_k}),其中(P_i(1leqslant ileqslant k))为n的互质因子,我们设(d=P_1^{y_1} imes P_2^{y_2} imes ... imes P_k^{y_k}),其中(0leqslant y_ileqslant x_i(1leqslant ileqslant k)),当存在一个(y_igeqslant2)的话,那么(mu(d)=0),因此我们只要考虑(y_i=0,1)的情况。假设d中含有r个n的互质因子,且这些质因子的指数为1,那么(mu(d)=(-1)^r),这样的d一共有(inom{k}{r})个。
      那么(sumlimits_{d|n} mu(d)=sumlimits_{r=0}^k inom{k}{r} imes (-1)^r=(1-1)^k=0)

    莫比乌斯函数(mu(n))是个积性函数,证明略。
    这说明(mu(n)=prodlimits_{i=1}^k mu(P_i^{x_i}))


    由于莫比乌斯函数的这些性质,使得它可以用欧拉筛在线性时间内求出

    3.莫比乌斯反演(性质/证明)
    首先我们证明一下第一个柿子的正确性

    [g(n)=sumlimits_{d|n}f(dfrac{n}{d}) imes mu(d)=sumlimits_{d|n}mu(d) sumlimits_{i|frac{n}{d}}g(i)Longrightarrowsumlimits_{i|n}g(i)sumlimits_{i imes d|n}mu(d)=sumlimits_{i|n}g(i)sumlimits_{d|frac{n}{i}}mu(d) ]

    箭头转换的时候,将(g(i))提前枚举了
    我们现在考虑一下(sumlimits_{d|frac{n}{i}}mu(d))的取值

    • 当i=n时,(sumlimits_{d|frac{n}{i}}mu(d)=1,g(i)sumlimits_{d|frac{n}{i}}mu(d)=g(n))
    • 当i为小于n的约数时,(sumlimits_{d|frac{n}{i}}mu(d)=0,g(i)sumlimits_{d|frac{n}{i}}mu(d)=0)

    所以(g(n)=sumlimits_{d|n}f(dfrac{n}{d}) imes mu(d))得证


    莫比乌斯函数有个性质:
    (f(n)/g(n))中的任意一个为积性函数后,另一个也同样为积性函数
    这个性质保证了其在之后能够进行线筛。
    证明略(证明太长,我懒得写)

    4.莫比乌斯函数的应用

    • (g(i))很难直接求,但(sumlimits_{d|i}g(d))很好求,我们就可以用莫比乌斯反演来求(g(i)):$$f(i)=sumlimits_{d|i}g(d)Rightarrow g(i)=sumlimits_{d|i}f(dfrac{i}{d}) imes mu(d)$$
    • (g(i))很难直接求,但(sumlimits_{d=1}^{frac{n}{i}}g(d))很好求,我们就可以用莫比乌斯反演来求(g(i)):$$f(i)=sumlimits_{d=1}^{frac{n}{i}}g(d imes i)Rightarrow g(i)=sumlimits_{d=1}^{frac{n}{i}}f(d imes i)mu(d)$$

    例题

    [POI2007]Zap
    Description
    FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。

    Input
    第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个正整数,分别为a,b,d。(1<=d<=a,b<=50000)

    Output
    对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。

    Sample Input
    2
    4 5 2
    6 4 3

    Sample Output
    3
    2

    HINT
    对于第一组询问,满足条件的整数对有(2,2),(2,4),(4,2)。对于第二组询问,满足条件的整数对有(6,3),(3,3)。

    Attention:为了方便书写,我们把x,y改成i,j,把多组数据的n改为T,把a,b改成n,m,并且我们让n<m

    首先我们列出本题要求的柿子

    [sumlimits_{i=1}^nsumlimits_{j=1}^m[gcd(i,j)=d] ]

    d看起来太讨厌,我们把它直接除掉

    [sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sumlimits_{j=1}^{lfloorfrac{m}{d} floor}[gcd(i,j)=1] ]

    然后我们发现最后面那一个长得和莫比乌斯函数很像,稍微改一下得到

    [sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sumlimits_{j=1}^{lfloorfrac{m}{d} floor}sumlimits_{x|i,x|j}mu(x) ]

    把枚举x的挪到前面

    [sumlimits_{x=1}^{lfloorfrac{n}{d} floor}mu(x)lfloordfrac{n}{dx} floorlfloordfrac{m}{dx} floor ]

    这个柿子终于变得小清新了,但是如果直接枚举x的话还是摆脱不了TLE的命运。。。
    注意到后面的(lfloordfrac{n}{dx} floorlfloordfrac{m}{dx} floor​)在很多情况下值都是一样的,那么我们进行数论分块即可
    总时间复杂度降为(O(Tsqrt n))

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x>=10)     print(x/10);
    	putchar(x%10+'0');
    }
    const int N=5e4;
    int prime[N+10],miu[N+10],sum[N+10];
    bool inprime[N+10];
    void prepare(){
    	miu[1]=1;
    	int tot=0;
    	for (int i=2;i<=N;i++){
    		if (!inprime[i])	prime[++tot]=i,miu[i]=-1;
    		for (int j=1;j<=tot&&i*prime[j]<=N;j++){
    			inprime[i*prime[j]]=1;
    			if (i%prime[j]==0){miu[i*prime[j]]=0;break;}
    			miu[i*prime[j]]=-miu[i];
    		}
    	}
    	for (int i=1;i<=N;i++)	sum[i]=sum[i-1]+miu[i];
    }
    int main(){
    	prepare();
    	for (int Data=read();Data;Data--){
    		int A=read(),B=read(),D=read();
    		ll Ans=0;
    		A/=D,B/=D;
    		int x=min(A,B),pos=0;
    		for (int d=1;d<=x;d=pos+1){
    			pos=min(A/(A/d),B/(B/d));
    			Ans+=1ll*(sum[pos]-sum[d-1])*(A/d)*(B/d);
    		}
    		printf("%lld
    ",Ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Perforce笔记
    Lumia 800 无法正常开机
    Windows service 中出现Set ServiceLogin 对话框
    华为要求七千员工先辞职再竞岗 补偿费超10亿
    BLOG新址:http://longware.spaces.live.com
    家装(2)
    解脱
    论持久战
    有感于软件项目测试
    THE POEM AS A GIFT FOR MY GF'S BIRTHDAY
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9475395.html
Copyright © 2011-2022 走看看