容斥与简单莫反

容斥与莫比乌斯函数

容斥原理:

介绍:设集合S1Sn,记|Si|表示集合Si的大小,设表示集合的并集运算,表示集合的交集运算,则

|i=1nSi|=i=1n|Si|1i<jn|SiSj|+1i<j<kn|SiSjSk|+(1)n+1|i=1nSi|

所以由容斥原理可以得到之前的多重集的组合数公式:

设集合S={n1·a1,n2·a2,n3·a3nk·ak}是由n1a1……组成的多重集,n=i=1kni
则从该集合中选出r(rn)个数组成的不同的多重集数量为:

Ck+r1k1i=1kCk+rni2k1+1i<jnCk+rninj2k1+(1)kCk+rnk1k1

对于容斥原理在代码中的实现:我们可以枚举x[0,2k1],将x内的含1的位提取出来,根据奇偶性判断是加还是减,特别的,我们令x=0代表Ck+r1k1

Mobius函数

莫比乌斯函数是一个容斥系数,与容斥原理息息相关

定义:设x被算术基本定理分解为:i=1npici

μ(x)={0i[1,n],ci21nmod2=0,i[1,n],ci=11nmod2=1,i[1,n],ci=1

则称μ(x)umobius函数

对于mobius函数的求法:

如果只是求一个数的莫比乌斯函数,分解质因数即可,若是求1N的,则使用埃拉托尼斯筛法计算

for(int i=1;i<=n;i++)mui[i]=1,vis[i]=0;
for(int i=2;i<=n;i++){  
    if(vis[i])continue;
    mui[i]=-1;
    vis[i]=1;
    for(int j=2;j*i<=n;j++){  
        mui[i*j]*=-1;
        if(j%i==0)mui[i*j]=0;
        vis[i*j]=1;
    }
}

性质:

1.对于任意正整数n,d|nμ(i)=[n=1]

2.若gcd(a,b)=1,则μ(ab)=μ(a)μ(b)

d|nμ(d)d=φ(n)n

莫比乌斯函数与容斥原理的关系:

即对1N应用容斥原理,则每个数的莫比乌斯函数决定了那个数的系数

随意扔一道例题:
ZAP-Queries

[POI2007]ZAP-Queries

题目描述

密码学家正在尝试破解一种叫 BSA 的密码。

他发现,在破解一条消息的同时,他还需要回答这样一种问题:

给出 a,b,d,求满足 1xa1yb,且 gcd(x,y)=d 的二元组 (x,y) 的数量。

因为要解决的问题实在太多了,他便过来寻求你的帮助。

输入格式

输入第一行一个整数 n,代表要回答的问题个数。

接下来 n 行,每行三个整数 a,b,d

输出格式

对于每组询问,输出一个整数代表答案。

数据规模与约定

对于全部的测试点,保证 1n5×1041da,b5×104

分析:
求有多少对二元组(x,y)满足(xa,yb)并且gcd(x,y)=k,等价于求有多少对二元组(x,y)满足(xak,ybk)并且x,y互质
D[a,b,k]表示满足xa,yb并且k|gcd(x,y)的二元组有多少对,显然,只需要x,yk的倍数即可,而1a中k的倍数有ak个,b同理,则我们很容易就可以得出D[a,b,k]=akbk

F[a,b]表示满足xa,yleb的二元组(x,y)有多少对,则有:

F[a,b]=i=1min(a,b)μ(i)×D[a,b,i]

上式含义:当i=1的时候D[a,b,1]×μ(1),而μ(1)=1,所以此时就相当于是加上了所有的二元组a×b,应当减去2,3,5,7的倍数,但是6,10等就被减去了两次需要在加回来一次……以此类推便可以确定对于每个数加减的系数都是μ函数

又联系我们之前学习的数论分块的知识
akbk这是呈段状的

i[x,min(aax,bbx)],akbk的值都相等,我们预处理μ函数的前缀和即可直接累加这一段答案

#define int long long
int T,n,a,b,d,mobius[50005],sum[50005];
bool vis[50005];
void init(){
    for(int i=1;i<=50000;i++)mobius[i]=1;
    for(int i=2;i<=50000;i++){
    	if(!vis[i]){
    		mobius[i]=-1;
    		for(int j=2;j*i<=50000;j++){
    			vis[j*i]=1;
    			mobius[i*j]= j%i==0?0:-mobius[i*j];
			}
		}
	}
    for(int i=1;i<=50000;i++)sum[i]=sum[i-1]+mobius[i];
}
int get(int a,int x){
    return a/(a/x);
}
signed main(){
    init();
	  scanf("%lld",&T);
    while(T--){
        int ans=0;
        scanf("%lld%lld%lld",&a,&b,&d);
        a/=d,b/=d;
        n=min(a,b);
        for(int l=1,r;l<=n;l=r+1){
            r=min(n,min(get(a,l),get(b,l)));
            ans+=(sum[r]-sum[l-1])*(a/l)*(b/l);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

莫比乌斯反演定理

仅作了解,tg无需掌握

设函数f(x),g(x)是定义在正整数集上的两个函数

形式1

若函数f(x),g(x)满足

f(n)=d|ng(d)=d|ng(nd)

则:

g(n)=d|nμ(d)f(nd)=d|nμ(nd)f(d)

形式2

若函数f(x),g(x)满足:

f(n)=n|dg(d)=n|dg(nd)

则有

g(n)=n|dμ(dn)f(d)=n|dμ(d)f(dn)

推一个大佬博客“浅谈”莫反

posted @   spdarkle  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示