容斥原理基础

文章目录

  • 容斥原理的引入
  • 从集合的角度考虑
  • 推广
  • 例子
    • 不被2、3、5整除的数
    • 错排问题
    • 求不定方程的解
    • Devu和鲜花

容斥原理的引入


从一个小学奥数问题引入:
一个班级有50人
喜欢语文的人有20人
喜欢数学的人有30人
同时喜欢语文数学的人有10人。
问题:

  1. 两门都不喜欢的有多少人
  2. 至少喜欢一个的有多少人

至少喜欢一门 20+30-10=40 都不喜欢 50-40=10


再将上面的课程门数进一步扩展为3门,问题变为
一个班级有60人
喜欢A的人有20人
喜欢B的人有30人
喜欢C的人有25人
同时喜欢AB的人有10人
同时喜欢AC的人有7人
同时喜欢BC的人有8人
同时喜欢ABC的人有2人

至少喜欢一门的人:A+B+C-AB-AC—BC+ABC=20+30+25-10-7-8+2=52 有60-52=8个同学一门都不喜欢


从集合的角度考虑

将上述问题抽象用数学的形式表示
∣ A ∪ B ∣ = ∣ A ∣ + ∣ B ∣ − ∣ A ∩ B ∣ |A \cup B|=|A|+|B|-|A \cap B| AB=A+BAB

∣ A ∪ B ∪ C ∣ = ∣ A ∣ + ∣ B ∣ + ∣ C ∣ − ∣ A ∩ B ∣ − ∣ A ∩ C ∣ − ∣ B ∩ C ∣ + ∣ − ∣ A ∩ B ∪ C ∣ |A \cup B \cup C|=|A|+|B|+|C|-|A \cap B|-|A \cap C|-|B \cap C|+|-|A \cap B \cup C| ABC=A+B+CABACBC+ABC


推广

image


例子

不被2、3、5整除的数

image

890. 能被整除的数

两种实现方法
虽然说理论上dfs只有 O ( 2 n ) O(2^n) O(2n)的复杂度,而二进制枚举的复杂度是 O ( m 2 n ) O(m2^n) O(m2n)但是实际上跑起来的效果二进制枚举跑的快很多,dfs还是跑的比较慢,可能是递归调用的开销比较大吧。
屏幕截图 2024-02-08 014954.png
屏幕截图 2024-02-08 015006.png


二进制枚举超集的写法


#include <bits/stdc++.h> 
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define pll pair<long long, long long>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back

using namespace std;

const int N=2e5+10;

void solve()
{
	int n,m;cin>>n>>m;
	vector<int>p(m);
	rep(i,0,m-1)	cin>>p[i];
	int ans=0;
	rep(i,1,(1<<m)-1){
		
		int sgn=0,mul=1;
		rep(j,0,m-1){
			if(i&(1<<j)){
				sgn++;
				if(mul*p[j]>n){
					mul=-1;
					break;
				}
				mul*=p[j];
			}
		}
		if(mul!=-1){
			if(sgn&1){
				//符号为正
				ans+=n/mul;
			}else{
				ans-=n/mul;
			}
		}
	}
	cout<<ans<<endl;
}

signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//   	freopen("1.in", "r", stdin);
  	int _;
//	cin>>_;
//	while(_--)
	solve();
	return 0;
}

dfs写法


#include <bits/stdc++.h> 
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define pll pair<long long, long long>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back

using namespace std;

const int N=2e5+10;

int ans=0,n,m;
vector<int>path;
vector<int>p(N);
void dfs(int u){
	if(u==m){
		if(!path.size()){
			return;
		}
		int sgn=path.size()&1?1:-1;
		int mul=1;
		for(auto i:path){
			if(mul>n){
				mul=0;
				break;
			}
			mul*=i;
		}
		if(mul)    ans+=n/mul*sgn;
		return;
	}
	dfs(u+1);
	path.pb(p[u]);
	dfs(u+1);
	path.pop_back();
};

void solve()
{
	cin>>n>>m;
	rep(i,0,m-1)	cin>>p[i];
	dfs(0);
	cout<<ans<<endl;
}

signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//   	freopen("1.in", "r", stdin);
  	int _;
//	cin>>_;
//	while(_--)
	solve();
	return 0;
}


错排问题

错排问题:
P i ≠ i , P i 为排列 P_i \not = i,P_i为排列 Pi=iPi为排列
image

求不定方程的解

image
如果没有对 X i X_i Xi进行限制的话,可以直接用隔板法去做,直接插入 n − 1 n-1 n1个隔板,答案就是 C ( m + n − 1 n − 1 ) C(_{m+n-1}^{n-1}) C(m+n1n1)
但是现在对于每一个 X i X_i Xi我们都有一个上限 b i b_i bi

考虑容斥原理
这道题目并没有明显的容斥不像上面的倍数
我们把 0 < = x i < = b i 0<=x_i<=b_i 0<=xi<=bi转化成
( x i > = 0 ) − ( x i > = b i + 1 ) (x_i>=0)-(x_i>=b_i +1) (xi>=0)(xi>=bi+1)
( x i > = 0 ) (x_i>=0) (xi>=0)可以理解为没有限制
( x i > = b i + 1 ) (x_i>=b_i +1) (xi>=bi+1)可以理解为最少选 b i + 1 b_i+1 bi+1个,做一个映射,可以用隔板法去做。
$ (^{m-b_i+1+n-1} _{n-1})$

#include <bits/stdc++.h> 
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define pll pair<long long, long long>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back

using namespace std;

const int N=2e5+10,mod=1e9+7;

int n,m,b[20];
int ifac,inv[20],ans;
int cal(int x){
	//C(x+n-1,n-1)
	//x+1,...,x+n-1/(n-1)!
	int ans=1;
	rep(i,1,n-1){
		ans=ans*(x+i)%mod;
	}
	ans=ans*ifac%mod;
	return ans;
}
void dfs(int d,int sgn, int sum){
	if(d==n){
		if(sum>m)	return;
		ans=(ans+sgn*cal(m-sum))%mod;
	}else{
		//x[i]>=0,当前这个没有违反
		dfs(d+1,sgn,sum);
		//x[i]>=b[i]+1,当前这个违反了
		dfs(d+1,-sgn,sum+b[d]+1);
	}
}

void solve()
{
	cin>>n>>m;
	//求n-1阶乘的逆元
	ifac=1;
	rep(i,1,n-1){
		if(i==1)	inv[i]=1;
		else inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		ifac=ifac*inv[i]%mod;
	}
	rep(i,0,n-1){
		cin>>b[i];
	}
	//第i个变量,容斥系数,数值之和
	dfs(0,1,0);
	cout<<ans<<endl;
}

signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
   	freopen("1.in", "r", stdin);
  	int _;
//	cin>>_;
//	while(_--)
	solve();
	return 0;
}

Devu和鲜花

这个是上面的题目套了一个皮套,本质上还是不定方程的求解


dfs写法


#include <bits/stdc++.h> 
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define pll pair<long long, long long>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back

using namespace std;

const int N=2e5+10,mod=1e9+7;

int n,m,b[22];
int ifac,inv[22],ans;
int cal(int x){
	//C(x+n-1,n-1)
	//x+1,...,x+n-1/(n-1)!
	int ans=1;
	rep(i,1,n-1){
		ans=ans%mod*(x%mod+i%mod)%mod;
	}
	ans=ans*ifac%mod;
	return ans;
}
void dfs(int d,int sgn, int sum){
	if(d==n){
		if(sum>m)	return;
		ans+=sgn*cal(m-sum)%mod;
// 		ans=(ans+sgn*cal(m-sum))%mod;
	}else{
		//x[i]>=0,当前这个没有违反
		dfs(d+1,sgn,sum);
		//x[i]>=b[i]+1,当前这个违反了
		dfs(d+1,-sgn,sum+b[d]+1);
	}
}

void solve()
{
	cin>>n>>m;
	ifac=1;
	rep(i,1,n-1){
		if(i==1)	inv[i]=1;
		else inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		ifac=ifac*inv[i]%mod;
	}
	rep(i,0,n-1){
		cin>>b[i];
	}
	//第i个变量,容斥系数,数值之和
	dfs(0,1,0);
	ans%=mod;
	if(ans<0)   ans+=mod;
	cout<<ans%mod<<endl;
}

signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//   	freopen("1.in", "r", stdin);
  	int _;
//	cin>>_;
//	while(_--)
	solve();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/377889.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

10个简单有效的编辑PDF文件工具分享

10个编辑PDF文件工具作为作家、编辑或专业人士&#xff0c;您可能经常发现自己在处理 PDF 文件。无论您是审阅文档、创建报告还是与他人共享工作&#xff0c;拥有一个可靠的 PDF 编辑器供您使用都非常重要。 10个简单适用的编辑PDF文件工具 在本文中&#xff0c;我们将介绍当今…

详细分析python中的 async 和 await(附Demo)

目录 前言1. 基本知识2. Demo2.1 Demo1&#xff08;同步&#xff09;2.2 Demo2&#xff08;错误&#xff09;2.3 Demo3&#xff08;不正确的异步&#xff09;2.4 Demo4&#xff08;正确异步&#xff09; 3. 完整版4. 拓展4.1 asyncio.create_task(coroutine)4.2 asyncio.gather…

FXTM富拓监管变更!2024开年连续3家交易商注销牌照

交易商的监管信息是经常发生变更的&#xff0c;即使第一次投资时查询平台监管牌照&#xff0c;投资者仍需持续关注其监管动态。千万不要以为第一步审核好后就万事大吉了&#xff01; 2024年开年&#xff0c;就有3家交易商的重要信息发生变更&#xff0c;注销其金融监管牌照&…

Java 将TXT文本文件转换为PDF文件

与TXT文本文件&#xff0c;PDF文件更加专业也更适合传输&#xff0c;常用于正式报告、简历、合同等场合。项目中如果有使用Java将TXT文本文件转为PDF文件的需求&#xff0c;可以查看本文中介绍的免费实现方法。 免费Java PDF库 本文介绍的方法需要用到Free Spire.PDF for Java…

编程实例分享,宠物诊所电子处方怎么开,兽医电子处方模板电子版操作教程

编程实例分享&#xff0c;宠物诊所电子处方怎么开&#xff0c;兽医电子处方模板电子版操作教程 一、前言 以下操作教程以 佳易王兽医电子处方软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、在系统 设置里可以设置打印参数&#x…

《动手学深度学习(PyTorch版)》笔记7.2

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…

单片机学习笔记---LED点阵屏的工作原理

目录 LED点阵屏分类 LED点阵屏显示原理 74HC595的介绍 一片74HC595的工作原理 多片级联工作原理 总结 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种公共场合&#xff0c;如汽…

go语言进阶篇——面向对象(一)

什么是面向对象 在我们设计代码时&#xff0c;比如写一个算法题或者写一个问题结局办法时&#xff0c;我们常常会使用面向过程的方式来书写代码&#xff0c;面向过程主要指的是以解决问题为中心&#xff0c;按照一步步具体的步骤来编写代码或者调用函数&#xff0c;他在问题规…

后端创建订单

package com.java1234.entity;import io.jsonwebtoken.Claims;/*** jwt验证信息* author java1234_小锋* site www.java1234.com* company Java知识分享网* create 2019-08-13 上午 10:00*/ public class CheckResult {private int errCode;private boolean success;private Cl…

Linux下的多线程

前面学习了进程、文件等概念&#xff0c;接下里为大家引入线程的概念 多线程 线程是什么&#xff1f;为什么要有线程&#xff1f;线程的优缺点Linux线程操作线程创建线程等待线程终止线程分离 线程间的私有和共享数据理解线程库和线程id深刻理解Linux多线程&#xff08;重点&a…

2023年全国职业院校技能大赛软件测试赛题第3套

2023年全国职业院校技能大赛 软件测试赛题第3套 赛项名称&#xff1a; 软件测试 英文名称&#xff1a; Software Testing 赛项编号&#xff1a; GZ034 归属产业&#xff1a; 电子与信息大类 …

软件价值10-数字时钟

这是一个数字时钟程序&#xff1a; # importing whole module from tkinter import * from tkinter.ttk import *# importing strftime function to # retrieve systems time from time import strftime# creating tkinter window root Tk() root.title(Clock)# This functio…

Docker Compose实例

目录 一、前提说明 二、简单的Docker容器部署案例 1. Dockerfile 配置 2. docker-compose.yml 配置 3. application.properties 配置 4. pom.xml 配置 5. 上传文件 6. 创建基础Docker镜像 7. docker-compose.yml编排 8. 停止并删除容器编排 一、前提说明 在配置好Do…

【博云2023】乘龙一跃腾云海,侧目抬手摘星河

癸卯渐远&#xff0c;甲辰渐至&#xff0c;预示着被汗水浇灌的种子&#xff0c;必将顶开冻土&#xff0c;迎接阳光。 每逢春节&#xff0c;当亲友彼此问候&#xff0c;博云人总能自豪地说&#xff0c;我们认真地、努力地奋斗&#xff0c;让我们能自信地踏上新的征程。 我们的…

使用Python进行数据的描述性分析,用少量的描述性指标来概括大量的原始数据

在进行数据分析时&#xff0c;当研究者得到的数据量很小时&#xff0c;可以通过直接观察原始数据来获得所有的信息。但是&#xff0c;当得到的数据量很大时&#xff0c;就必须借助各种描述性指标来完成对数据的描述工作。用少量的描述性指标来概括大量的原始数据&#xff0c;对…

用户和文件权限管理

一、用户管理 1、创建用户 [rootmaster ~]# useradd maple [rootmaster ~]# ll /home total 0 drwx------ 2 maple maple 62 Feb 7 20:47 maple drwx------ 2 www www 62 Jan 17 21:05 www [rootmaster ~]# passwd maple Changing password for user maple. New passwor…

Swift Combine 发布者publisher的生命周期 从入门到精通四

Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三 1. 发布者和订阅者的生命周期 订阅者和发布者以明确定义的顺序进行通信&#xff0c;因此使得它们具有从开始到结束的生命周期&#xff1a; …

深度学习系列56:使用whisper进行语音转文字

1. openai-whisper 这应该是最快的使用方式了。安装pip install -U openai-whisper&#xff0c;接着安装ffmpeg&#xff0c;随后就可以使用了。模型清单如下&#xff1a; 第一种方式&#xff0c;使用命令行&#xff1a; whisper japanese.wav --language Japanese --model…

12. BI - 可视化在项目蒸汽量预测的过程及应用

本文为 「茶桁的 AI 秘籍 - BI 篇 第 12 篇」 文章目录 工业蒸汽量预测 Hi, 你好。我是茶桁。 我们今天继续来看数据可视化做数据探索&#xff0c;今天我们还是来看相关项目。来看看可视化 EDA 在项目中的应用。 工业蒸汽量预测 接下来这个项目&#xff0c;是在阿里天池上的一…