zoukankan      html  css  js  c++  java
  • 【模板】莫比乌斯反演

    一、莫比乌斯反演

    我们先来看一个函数:(F(x)=sum_{dmid x} f(d))
    我们先枚举一下这个函数的各个值

    (F(1)=f(1))

    (F(2)=f(1)+f(2))

    (F(3)=f(1)+f(3))

    (F(4)=f(1)+f(2)+f(4))

    (F(5)=f(1)+f(5))

    (F(6)=f(1)+f(2)+f(3)+f(6))

    (F(7)=f(1)+f(7))

    (F(8)=f(1)+f(2)+f(4)+f(8))

    于是,我们可以反过来推导出关于(f(n))的关系式

    (f(1)=F(1))

    (f(2)=F(2)-F(1))

    (f(3)=F(3)-F(1))

    (f(4)=F(4)-F(2)-F(1))

    (f(5)=F(5)-F(1))

    (f(6)=F(6)-F(3)-F(2)+F(1))

    (f(7)=F(7)-F(1))

    (f(8)=F(8)-F(4))

    我们可以得到(F(x)=sum_{dmid x} f(d)Rightarrow f(x)=sum_{dmid x}mu(d)F(frac{n}{d})qquad)

    其中,我们可以了解到一个新的函数:莫比乌斯函数

    二、莫比乌斯函数:(mu(x))

    这是莫比乌斯函数,定义如下
    1. (x=1),则 (mu(x)=1)

    2. (x=p{1}p{2}p{3}dots p{k}),且(p{i})为互不相同的质数,则有(mu(x)=(-1)^k)

    3. 其他情况中 (mu(x)=0)


    莫比乌斯函数中有用的性质还是挺多的,这里就只列出一个最常用的炒鸡重要的性质

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

    这条性质可以运用到很多与(gcd)有关的题目中的推导式子中,非常重要

    同时,莫比乌斯函数还是一个积性函数
    在这里给大家提及一下积性函数(f):既当(gcd(i,j)=1)时,(f(xy)=f(x)f(y))的函数叫积性函数
    积性函数的性质
    1. (f(1)=1)
    2. 积性函数的前缀和也是积性函数

    莫比乌斯函数就是借助了它是积性函数的特点,使其可以通过线性筛得到

    求莫比乌斯函数(mu)的代码
    inline void init()
    {
    	mu[1]=1;
    	for(int i=2;i<N;i++)
    	{
    		if(!vis[i])
    		{
    			prime[++cnt]=i;
    			mu[i]=-1;
    		}
    		for(int j=1;j<=cnt&&i*prime[j]<N;j++)
    		{
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0)break;
    			mu[i*prime[j]]=-mu[i];
    		}
    	}
    }
    

    莫比乌斯反演和函数可以运用在很多题目的公式推导上,重点还是公式的推导


    三、整除分块

    整除分块是在莫比乌斯反演题中重要的一环,将询问的复杂度的从(O(n))优化成(O(sqrt n)),可以成功解决大多数数据较大的题目,十分重要
    整除分块用于求(sum_{i=1}^nleft lfloor frac{n}{i} ight floor)的普遍情况(并不强制如上形式)下,只要满足有规律的一段区间中的值是相同的,就可以用整除分块。我们来看看对于较简单的整除分块。

    若令(n=22,x=left lfloor frac{n}{i} ight floor),则有:

    (i=1)时,(x=22)

    (i=2)时,(x=11)

    (i=3)时,(x=7)

    (i=4)时,(x=5)

    (i=5)时,(x=4)

    (i=6)时,(x=3)

    (i=7)时,(x=3)

    (i=8)时,(x=2)

    (i=9)时,(x=2)

    (i=10)时,(x=2)

    (i=11)时,(x=2)

    (i=12)时,(x=1)

    (i=13)时,(x=1)

    (vdots)

    (i=22)时,(x=1)

    由上可以看到,由几段区间的(x)是相同的,我们可以通过(l=(上一次的r) +1,r=n/(n/l))得到区间([l,r]),可以(O(1))时间算出这段区间的(x)的和,最后起到求和的作用
    void solve()
    {
    	int ans=0;
    	for(int l=1,r;l<=n;l=r+1)
    	{
    		r=n/(n/l);
    		ans+=(r-l+1)*(n/(n/l));
    	}
    }
    
  • 相关阅读:
    在VC中设置某些文件不参加编译的方法
    VC7/VC8开发的库在VC6中的使用问题转载
    *.tar.bz2文件解压
    设置VC工程为Debug或Releas版本的方法
    Linux下设置环境变量命令export
    Source insight中设置字体方法
    双系统或虚拟机中与主机时间不一致解决方法
    制作启动光盘方法
    Linux下nfs服务器搭建
    ghost的备份与恢复转载
  • 原文地址:https://www.cnblogs.com/ShuraEye/p/11354750.html
Copyright © 2011-2022 走看看