zoukankan      html  css  js  c++  java
  • 莫比乌斯反演

    莫比乌斯反演

    前置知识

    数论分块

    数论分块,还可以称为整除分块。

    可以注意到,对于一个数 (n) , (lfloor frac{n}{i} floor) 呈现一种块状分布,并且对于 (lfloor frac{n}{i} floor) 的一块来说,最后一个数是(lfloorfrac{n}{lfloor frac{n}{i} floor} floor)

    证明:

    [frac{n}{i}=lfloorfrac{n}{i} floor+rquad (r<1)\ implies lfloorfrac{n}{lfloorfrac{n}{i} floor} floorgeqlfloorfrac{n}{lfloorfrac{n}{i} floor+r} floor =lfloorfrac{n}{frac{n}{i}} floor\ implies lfloorfrac{n}{lfloorfrac{n}{i} floor} floorgeq i ]

    而这时我们就可以一块一块的处理了,而块数数量级为 (O(sqrt{n})) ,证明如下:

    • 对于 (ileqsqrt{n}) ,就算每个 (i) 取值都不同, (lfloor frac{n}{i} floor) 最多也只有 (sqrt{n}) 种取值。
    • 对于 (igeqsqrt{n})(lfloor frac{n}{i} floorleqsqrt{n}) ,自然最多有 (sqrt{n}) 种取值。
    • 所以 (lfloor frac{n}{i} floor) 的取值有 (O(sqrt{n})) 种。

    我们举个例子,求:

    [sum_{i=1}^{n}k; mod;i ]

    乍一看和分块没有联系,那么我们化一下:

    [sum_{i=1}^{n}k-lfloorfrac{k}{i} floor ]

    其中 (k) 的区间和是可以 (O(1)) 求的,而通过整除分块,我们也可以 (O(sqrt{n})) 求出后面的减项的区间和,这样就吧 (O(n)) 的复杂度降到了 (O(sqrt{n}))

    积性函数

    如果一个函数 (f) 有:

    [f(xy)=f(x) imes f(y)quad if;xot y ]

    我们就把 (f) 称作积性函数。

    常见的积性函数有:

    • (varphi) :欧拉函数
    • (I) :不变函数,恒为 (1)
    • (x^a) :幂函数
    • (epsilon) :单位元,只有 (epsilon(1)=1) ,其它为 (0)
    • (d) :约数个数函数
    • (sigma) :约数和函数
    • (mu) :莫比乌斯函数,详见下文

    这里有一个小结论:

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

    如果 (f) 是积性函数,那么 (g) 也是积性函数。

    证明:

    [xot y\ g(x) imes g(y)=sum_{i|x}f(i)sum_{j|y}f(j)\ =sum_{i|x}sum_{j|y} f(ij) \ =sum_{d|xy}f(d)\ =g(xy) ]


    由于积性函数性质特殊,我们经常需要线性筛来求。

    Dirichlet 卷积

    定义 (Dirichlet) 卷积为:

    [f=g*hiff f(n)=sum_{d|n}g(d)h(frac{n}{d}) ]


    卷积满足的定律有:

    • 交换律:

      这里有个小定理:

    [sum_{d|n}f(d)=sum_{d|n}f(frac{n}{d}) ]

    ​ 很显然成立,因为 (n) 的因数是成对的。

    ​ 那么就显然:

    [g*h=h*g ]

    • 结合律:

      同样有一个小技巧,对于二重和式:

      [sum_{d|n}sum_{x|d}F(d,x) ]

      我们可以将 (d=lx) 代入式中,从而将 (x) 换成第一个枚举项:

      [sum_{d|n}sum_{x|d}F(d,x)=sum_{x|n}sum_{xl|n}F(lx,x) =sum_{x|n}sum_{l|frac{n}{x}}F(xl,x) ]

      应用到结合律证明中:

      [(f*g)*h=f*(g*h)\ implies sum_{d|n}sum_{x|d}f(x)g(frac{d}{x})h(frac{n}{d})=sum_{d|n}sum_{x|d}f(frac{n}{d})g(frac{d}{x})h(x)\ impliessum_{d|n}sum_{x|d}f(x)h(frac{n}{d})=sum_{d|n}sum_{x|d}f(frac{n}{d})h(x)\ implies sum_{x|n}sum_{l|frac{n}{x}}f(x)h(frac{n}{lx})=sum_{d|n}sum_{x|d}f(frac{n}{d})h(x)\ implies sum_{x|n}sum_{l|x}f(frac{n}{x})h(frac{x}{l})=sum_{d|n}sum_{x|d}f(frac{n}{d})h(x)\ implies sum_{x|n}sum_{l|x}f(frac{n}{x})h(l)=sum_{d|n}sum_{x|d}f(frac{n}{d})h(x) ]

      可以发现只是换了个符号,两式等价。

    • 分配律:

      [sum_{d|n}[f(d)+g(d)]h(frac{n}{d})=sum_{d|n}f(d)h(frac{n}{d})+sum_{d|n}g(d)h(frac{n}{d}) ]

      显然成立。


    常见卷积:

    • (d=I*I=sum_{d|n} 1)

    • (n=varphi*I=sum_{d|n}varphi(d)) ,这个卷积被称作 欧拉反演 ,证明如下:

      对于质数的幂次 (p^k)

      [sum_{d|p^k}varphi(d)=1+(p-1)+(p^2-p)+cdots+(p^k-p^{k-1})=p^k ]

      又因为此式是积性函数,所以对于任意的 (x=p_1^{a_1}p_2^{a_2}cdots p_r^{a_r})

      [sum_{d|x}varphi(d)=sum_{d|p_1^{a_1}}varphi(d)sum_{d|p_2^{a_2}}varphi(d)cdotssum_{d|p_r^{a_r}}varphi(d)=p_1^{a_1}p_2^{a_2}cdots p_r^{a_r}=x ]

    • (sigma=n*I=sum_{d|n}d) ,代入上面那个结论可得:(sigma=varphi*d)

    莫比乌斯函数

    莫比乌斯函数 (mu) 如下定义:

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

    ([n==1]) 表示一个 (bool) 表达式,为真时返回 (1) ,否则返回 (0)

    卷积表示为 :

    [epsilon=mu*I ]

    而详细的 (mu) 值为:

    [mu(x)= egin{cases} 1 & ext{$x=1$}\ (-1)^r & ext{$x=p_1p_2dots p_r$}\ 0 & ext{else} end{cases} ]

    第二项表示,对 (x) 因式分解后,如果质因子都是一次幂,(mu) 值为 (1) , 如果有任意一个质因子幂次大于等于 (2) ,那么 (mu) 值为 (0)

    看到这里,大概已经很懵逼 (mu) 如此奇怪的值了,实际上,(mu) 的定义是为了进行反演,所以并不是基于单个值,而是基于卷积,单个值只是解出来的,所以讨论单个值没有意义。

    莫比乌斯反演

    对于函数:

    [F=f*Iiff F(n)=sum_{d|n}f(d) ]

    莫比乌斯函数可以使得:

    [f=F*muiff f(n)=sum_{d|n}mu(frac{n}{d})F(d) ]


    证明:(用到了上面证结合律和交换律的小技巧)

    [egin{align} sum_{d|n}mu(frac{n}{d})F(d)=sum_{d|n}mu(frac{n}{d})sum_{x|d}f(x)\ =sum_{d|n}sum_{x|d}mu(frac{n}{d})f(x)\ =sum_{x|n}sum_{l|frac{n}{x}}mu(frac{n}{xl})f(x)\ =sum_{x|n}f(x)sum_{l|frac{n}{x}}mu(l)\ =sum_{x|n}f(x)[frac{n}{x}==1]\ =f(n) end{align} ]

    除了 (d|n) 型以外,莫比乌斯反演还更常用到 (n|d) 的形式:

    [F(n)=sum_{n|d}f(d)\ f(n)=sum_{n|d}mu(frac{d}{n})F(d) ]

    证明:

    [egin{align} sum_{n|d}mu(frac{d}{n})F(d)=sum_{n|d}sum_{d|x}mu(frac{d}{n})f(x)\ =sum_{n|d}sum_{d|x}mu(frac{d}{n})f(x)\ f 将 m d=frac{x}{k} f代入 m\ =sum_{n|x}f(x)sum_{k|frac{x}{n}}mu(frac{x}{nk})\ =sum_{n|x}f(x)sum_{k|frac{x}{n}}mu(k)\ =sum_{n|x}f(x)[frac{x}{n}==1] =f(n) end{align} ]

    当然也可以用卷积定义去证明:

    [F=f*Iimpliesmu*F=f*I*muimplies F*mu=f*epsilonimplies f=F*mu ]


    有了莫比乌斯反演,我们在题目中就可以通过可能较好表示的 (f) 的卷积来反推 (f)

    例题

    YY的GCD

    题目是让求:

    [sum_{i=1}^{N}sum_{j=1}^{M}[gcd(i,j)==p]quad pin prime ]

    多组数据,(Tleq1e4)(N,Mleq1e7)

    首先不妨设 (Nleq M)

    然后我们设 (f(x))(gcd)(x) 的数的对数 ,(F(x)) 是公约数(不是最大公约数)的个数。

    显然有:

    [f(n)=sum_{i=1}^{N}sum_{j=1}^{M}[gcd(i,j)==n]\ F(n)=sum_{n|d}^{N}f(d)=lfloor frac{N}{n} floorlfloor frac{M}{n} floor\ herefore f(n)=sum_{n|d}^{N}mu(frac{d}{n})F(d) ]

    而我们要求的是:

    [egin{align} sum_{p}^{N}f(p) =sum_{p}^{N}sum_{p|d}^{N}mu(frac{d}{p})lfloor frac{N}{d} floorlfloor frac{M}{d} floor ag{$pin prime$} end{align} ]

    如果直接枚举 (p) ,后面得一个个算 (lfloor frac{N}{d} floor),需要 (O(T imes prime imessqrt{N})) 的复杂度 。是过不了这题的。

    我们需要换一个枚举项,好预处理。

    我们尝试枚举 (d) :

    [sum_{d=1}^{N}lfloor frac{N}{d} floorlfloor frac{M}{d} floorsum_{p|d}mu(frac{d}{p}) ]

    如此一来前半部分可以数论分块求出。问题就到了后半部分。

    我们发现,后半部分竟然可以线性筛出!

    我们设 (h(x)=sum_{p|x}mu(frac{x}{p}))

    • 对于 (x) 是质数的情况,很显然 (h(x)=mu(1)=1)

    • 对于递推情况 (h(x imes p),;pin prime)

      (p) 不是 (x) 已有的质因子,原来的 (mu) 项中都会多一个质因子,值取负,再加上新增的一项 (mu(x))

      (p)(x) 已有的质因子,但是只有一次幂,那么,除了 (mu(frac{x imes p}{p})) 的一项外,其他项都变为 (0) ,所以值为 (mu(x))

      (x) 中有大于等于二次幂的 (p) 因子,值直接为 (0)

    总结起来就是:

    [h(p)=1\ h(x imes p)= egin{cases} mu(x)-f(x) & ext{$x\%p eq0$}\ mu(x) & ext{$x\%p=0$ & $(x/p)\%p eq0$}\ 0 & ext{else} end{cases} ]

    那么线性筛出 (h) ,并处理出其前缀和,然后数论分块就可以达到 (O(N+T imes sqrt{N})) 的复杂度了。

    (frak Code)

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MAXN 10000000
    
    long long ans;
    int n,m,t;
    int tot;
    int prime[1000050],inp[10000050],mu[10000050],su[10000050],sum[10000050];
    
    void prework(){
    	inp[0]=inp[1]=1;
    	mu[1]=1;
    	su[1]=0;
    	sum[0]=sum[1]=0;
    	for(int i=2;i<=MAXN;i++){
    		if(!inp[i]){
    			prime[++tot]=i;
    			mu[i]=-1;
    			su[i]=mu[1];
    		}
    		for(int j=1;j <= tot && 1ll*prime[j]*i <= MAXN;j++){
    			int tp=prime[j]*i;
    			inp[tp]=1;
    			if(i%prime[j]==0){
    				mu[tp]=0;
    				if((i/prime[j])%prime[j] == 0)
    					su[tp]=0;
    				else
    					su[tp]=mu[i];
    				
    				break;
    			}
    			su[tp]=mu[i]-su[i];
    			mu[tp]=-1*mu[i];
    		}
    		
    		sum[i]=sum[i-1]+su[i];
    	}
    }
    
    
    int main()
    {
    	scanf("%d",&t);
    	
    	prework();
    	
    	while(t--){
    		ans=0;
    		scanf("%d %d",&n,&m);
    		if(m<n) swap(n,m); 
    		
    		for(int i=2;i<=n;i++){
    			int lt=min(n,min(n/(n/i),m/(m/i)));
    			ans+=1ll*(sum[lt]-sum[i-1])*(n/i)*(m/i);
    			i=lt;
    		}
    		
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
     
     
    

    声明及感谢

    部分内容参考自:


    内容采用“知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议”进行许可。请您在转载时注明来源及链接。


    (frak by;thorn\_)

  • 相关阅读:
    WPF项目学习.一
    AtCoder Beginner Contest 210 A~D 题解
    P7715 「EZEC-10」Shape 题解
    P6216 回文匹配 题解
    字符串学习笔记
    #2742. 「JOI Open 2016」销售基因链
    树状数组学习笔记
    2021 省选游记
    AtCoder Beginner Contest 196 E
    AtCoder Regular Contest 113 A~D题解
  • 原文地址:https://www.cnblogs.com/thornblog/p/12358447.html
Copyright © 2011-2022 走看看