容斥原理 训练笔记

容斥原理

设S是一个有限集,A_1,A_2…A_n是S的n个子集,则

∣ S − ⋃ i = 1 n A i ∣ = ∑ i = 0 n ( − 1 ) i ∑ 1 ≤ j 1 < j 2 . . . < j i ≤ n ∣ ⋂ k = 1 i A j k ∣ |S-\bigcup_{i=1}^{n}A_i|=\sum_{i=0}^{n}(-1)^i\sum_{1\leq j_1< j_2...<j_i \leq n}|\bigcap_{k=1}^{i}A_{j_k}| Si=1nAi=i=0n(1)i1j1<j2...<jink=1iAjk

基本应用:

m件不同的物品,分给n个人,要求每一个人至少分得一件物品,求不同的分配方案数

A i A_i Ai表示第i个人没有物品, S S S表示 m m m个物品分给 n n n个人的总方案数

∣ S − ⋃ i = 1 n A i ∣ = ∑ i = 0 n ( − 1 ) i ∑ 1 ≤ j 1 < j 2 . . . < j i ≤ n ∣ ⋂ k = 1 i A j k ∣ |S-\bigcup_{i=1}^{n}A_i|=\sum_{i=0}^{n}(-1)^i\sum_{1\leq j_1< j_2...<j_i\leq n}|\bigcap_{k=1}^{i}A_{j_k}| Si=1nAi=i=0n(1)i1j1<j2...<jink=1iAjk

= ∑ i = 0 n ( − 1 ) i ( n i ) ( n − i ) m =\sum_{i=0}^{n}(-1)^i\binom{n}{i}(n-i)^m =i=0n(1)i(in)(ni)m

2 n 2n 2n个元素 a 1 , a 2 , . . . , a n a_1,a_2, ...,a_n a1,a2,...,an b 1 , b 2 , . . . , b n b_1,b_2, ...,b_n b1,b2,...,bn,求有多少个它们的全排列,满足任意的

1 ≤ i ≤ n 1 \leq i \leq n 1in, a i a_i ai b i b_i bi 都不相邻。

同样的,令 A i A_i Ai表示 a i a_i ai b i b_i bi相邻,

∣ S − ⋃ i = 1 n A i ∣ = ∑ i = 0 n ( − 1 ) i ∑ 1 ≤ j 1 < j 2 . . . j i ≤ n ∣ ⋂ k = 1 i A j k ∣ |S-\bigcup_{i=1}^{n}A_i|=\sum_{i=0}^{n}(-1)^i\sum_{1\leq j_1< j_2...j_i \leq n}|\bigcap_{k=1}^{i}A_{j_k}| Si=1nAi=i=0n(1)i1j1<j2...jink=1iAjk
= ∑ i = 0 n ( − 1 ) i ( n i ) ∣ 有 i 对相邻的方案数 ∣ =\sum_{i=0}^{n}(-1)^i\binom{n}{i}|有i对相邻的方案数| =i=0n(1)i(in)i对相邻的方案数
= ∑ i = 0 n ( − 1 ) i ( n i ) 2 i ∗ ( 2 n − i ) ! =\sum_{i=0}^{n}(-1)^i\binom{n}{i}2^i*(2n-i)! =i=0n(1)i(in)2i(2ni)!

有了以上基本常识就可以上大招了

例题

CF449D

大意:
给出一个长度为n的序列 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an。求从中选择一个非空子集使得他们的按位与之和等于0的方案数

思路:
不考虑复杂度的话我们有一个非常套路的容斥做法。考虑性质Ai表示子集与之后第i位为1,那么我们的答案其实就是
∣ Ω − A 1 ⋃ A 2 . . . ⋃ A 20 ∣ = ∑ i = 0 20 ( − 1 ) i ∑ 1 ≤ j 1 < j 2 . . . < j i ≤ 20 ∣ A j 1 ⋃ A j 2 . . . A j i ∣ |\Omega -A_1\bigcup A_2...\bigcup A_{20}|=\sum_{i=0}^{20}(-1)^i\sum_{1\leq j_1 < j_2...<j_i \leq 20 }|A_{j_1}\bigcup A_{j_2}...A_{j_i}| ∣ΩA1A2...A20=i=020(1)i1j1<j2...<ji20Aj1Aj2...Aji
其中||符号就表示集合的大小

显然就可以状压枚举,这样的时间复杂度是 O ( n ∗ 1 e 6 ) O(n*1e6) O(n1e6),考虑优化。

注意到对于 ∣ A j 1 ⋃ A j 2 . . . A j i ∣ |A_{j_1}\bigcup A_{j_2}...A_{j_i}| Aj1Aj2...Aji,我们记满足对应所有性质的元素的个数为k,则该集合的大小就是 2 k − 1 2^k-1 2k1,那么什么元素会满足这些性质呢?就是二进制为其超集的元素呗,其价值就是1.

所以我们只要做一遍超集后缀和即可,时间复杂度来到 O ( 20 ∗ 1 e 6 ) O(20*1e6) O(201e6)

code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const ll N=1e5+10;
const ll mod=1e9+7;
ll n,cnt=0,a;
ll mas[N];
ll up=20;
ll vis[30];
ll dp[(1<<20)+10];
ll ksm(ll x,ll y)
{ll ans=1;while(y){if(y&1) ans=ans*x%mod;x=x*x%mod;y>>=1;}return ans;
}
ll gt()
{ll tot=0;ll fl;for(int i=1;i<=n;++i){fl=1;for(int j=0;j<up;++j){if(!vis[j]) continue;if((mas[i]&(1<<j))==0){fl=0;break;}}if(fl) tot++;}return ((ksm(2,tot)-1)%mod+mod)%mod;
}
void solve()
{cin>>n;for(int i=1;i<=n;++i) cin>>a,dp[a]++;for(int j=0;j<up;++j){for(int i=0;i<(1<<up);++i){if((i&(1<<j))==0) dp[i]+=dp[i^(1<<j)];}}ll ans=0;for(int s=0;s<(1<<up);++s){cnt=0;for(int i=0;i<up;++i) if(s&(1<<i)) cnt++;if(cnt%2) ans=((ans-ksm(2,dp[s])+1)%mod+mod)%mod;else ans=((ans+ksm(2,dp[s])-1)%mod+mod)%mod;}cout<<ans<<endl;
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}

CF1799G

大意:
在这里插入图片描述

思路:
个人认为这道题还是很顶的

题目有两个限制:每个人要得到 c i c_i ci票,每个人不能投给自己组

然后这里就有一个很巧妙的转化:我们可以先将同一个组的人放在一起来看,这样就可以将第一个限制稍微弱化一些,最后我们再想办法处理组内的方案数

那么此时的问题如下:每一个组 i i i总共有 n u m i num_i numi人,总共需要 f i f_i fi票,组内的人不能投给自己组,求合法方案数

考虑生成函数处理

我们用 a i a_i ai来表示第 i i i组的变元。那么对于第 i i i组的每一个人来说,它能投给除了自己组外的任河组,所以它的贡献是 a 1 + a 2 + . . . + a i − 1 + a i + 1 + . . . + a n a_1+a_2+...+a_{i-1}+a_{i+1}+...+a_n a1+a2+...+ai1+ai+1+...+an,我们可以简单记为 s − a i s-a_i sai,其中s就表示 ∑ i = 1 n a i \sum_{i=1}^{n}a_i i=1nai

那么我们最后得到式子为 ( s − a 1 ) n u m 1 ( s − a 2 ) n u m 2 . . . ( s − a n ) n u m n (s-a_1)^{num_1}(s-a_2)^{num_2}...(s-a_n)^{num_n} (sa1)num1(sa2)num2...(san)numn,记为 S S S,而我们的答案显然就是 [ a 1 f 1 a 2 f 2 . . . a n f n ] ( S ) [a_1^{f_1}a_2^{f_2}...a_n^{f_n}](S) [a1f1a2f2...anfn](S).此时不难发现,对于 a i a_i ai的指数,每一个s都可以提供1,而 ( s − a i ) n u m i (s-a_i)^{num_i} (sai)numi中的 − a i -a_i ai也可以提供不多于 n u m i num_i numi的指数。

所以我们考虑每一个 a i a_i ai的次数 det ⁡ i ( d e t i ≤ n u m i , d e t i ≤ f i ) \det_i(det_i \leq num_i,det_i \leq f_i) deti(detinumi,detifi),则每一个i有一个从 n u m i num_i numi中选择 d e t i det_i deti的方案数 ( n u m i d e t i ) \binom{num_i}{det_i} (detinumi),并且 d e t i det_i deti会提供 ( − 1 ) d e t i (-1)^{det_i} (1)deti的系数,然后剩下的所有指数都由 s s s提供,总共是 ∑ f i − ∑ d e t i = n − ∑ d e t i \sum f_i-\sum det_i=n-\sum det_i fideti=ndeti,要分成若干堆,第i堆有 f i − d e t i f_i-det_i fideti个,所以其实是一个可重集,不同组之间是相乘的关系,那么最终的答案其实就是
a n s = ∑ d e t i ≤ f i ( − 1 ) ∑ d e t i ∏ ( ( n u m i d e t i ) ) ( ( n − ∑ d e t i ) ! ( f 1 − d e t 1 ) ! ( f 2 − d e t 2 ) ! . . . ( f n − d e t n ) ! ) ans=\sum_{det_i\leq f_i}(-1)^{\sum det_i}\prod (\binom{num_i}{det_i})\binom{(n-\sum det_i)!}{(f_1-det_1)!(f_2-det_2)!...(f_n-det_n)!} ans=detifi(1)deti((detinumi))((f1det1)!(f2det2)!...(fndetn)!(ndeti)!)
= ∏ n u m i ∗ ∑ d e t i ≤ f i ( − 1 ) ∑ d e t i ( n − ∑ d e t i ) ! ∏ d e t i ! ( n u m i − d e t i ) ! ( f i − d e t i ) ! =\prod num_i *\sum_{det_i\leq f_i}(-1)^{\sum det_i}\frac{(n-\sum det_i)!}{\prod det_i!(num_i-det_i)!(f_i-det_i)!} =numidetifi(1)detideti!(numideti)!(fideti)!(ndeti)!

那么其实n只有200,所以我们可以比较轻松地来得到这个式子的结果

考虑枚举 ∑ d e t i \sum det_i deti,我们记为 d d d,那么再记一个 d p i , j dp_{i,j} dpi,j表示当前处理到了第i组, ∑ x ≤ i d e t i = j \sum_{x \leq i}det_i=j xideti=j,显然只要在过程中枚举合法的 d e t i det_i deti就能完成这个dp了,外层枚举d,内层枚举i,j,最内层枚举 d e t i det_i deti,乍一看时间复杂度好像是 O ( n 4 ) O(n^4) O(n4),但是因为 d e t i ≤ n u m i det_i \leq num_i detinumi,而 ∑ n u m i = n \sum num_i=n numi=n,所以实际复杂度只有 O ( n 3 ) O(n^3) O(n3)

这样我们就完成了组与组之间的关系。考虑组内部的票数分配, n u m i num_i numi个人,每一个人需要 c i c_i ci票,总共 ∑ c i = f i \sum c_i=f_i ci=fi票,所以这其实还是一个多重集,那么我们只要乘上系数 f i ! ∏ c i ! \frac{f_i!}{\prod c_i!} ci!fi!即可

推推式子还是有点累的~

code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const ll N=210;
const ll mod=998244353;
ll n;
ll f[N],t[N],c[N],num[N];//每一组的总期望票数,组别,个人期望票数,每组人数
ll dp[N][N];
ll ksm(ll x,ll y)
{ll ans=1;while(y){if(y&1) ans=ans*x%mod;x=x*x%mod;y>>=1;}return ans;
}
ll inv(ll x)
{return ksm(x,mod-2);
}
ll p[N],pp[N];
void init(ll n)
{p[0]=1;for(ll i=1;i<=n;++i) p[i]=p[i-1]*i%mod;pp[n]=inv(p[n]);for(int i=n-1;i>=0;--i) pp[i]=pp[i+1]*(i+1)%mod;}
void solve()
{init(200);// for(int i=1;i<=10;++i) cout<<p[i]<<" "<<pp[i]<<endl;cin>>n;for(int i=1;i<=n;++i) cin>>c[i];//期望票数for(int i=1;i<=n;++i) cin>>t[i],f[t[i]]+=c[i];for(int i=1;i<=n;++i) num[t[i]]++;ll ans=1,sum=0;for(int i=1;i<=n;++i) ans=ans*p[num[i]]%mod;for(int d=0;d<=n;++d)//det_i之和{for(int i=1;i<=n;++i) for(int j=0;j<=n;++j) dp[i][j]=0;dp[0][0]=p[n-d];for(int i=1;i<=n;++i){//当前枚举到第i组for(int j=0;j<=d;++j)//到第i个人位置det_i的总和为j{for(int k=0;k<=min(f[i],num[i])&&k<=j;++k)//det_i=k{ll det=pp[k]*pp[num[i]-k]%mod*pp[f[i]-k]%mod;dp[i][j]=(dp[i][j]+det*dp[i-1][j-k]%mod)%mod;}}}if((d%2)==0) sum=(sum+ans*dp[n][d]%mod)%mod;else sum=((sum-ans*dp[n][d]%mod)%mod+mod)%mod;}for(int i=1;i<=n;++i)//组内多重集{sum=sum*p[f[i]]%mod*pp[c[i]]%mod;}cout<<sum<<endl;
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();return 0;
}

未完待续

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

okvis

论文 Keyframe-Based Visual-Inertial SLAM Using Nonlinear Optimization 摘要 由于两种感知模式的互补性&#xff0c;视觉和惯性线索的融合在机器人中变得很流行。虽然迄今为止大多数融合策略都依赖于过滤方案&#xff0c;但视觉机器人界最近转向了非线性优化方法&#x…

【React Native】学习记录(二)——路由搭建和常见的开发技巧

模拟器设置成中文 在开发过程中发现&#xff0c;两个模拟器都不能输入中文&#xff0c;所以需要配置一下。 先说一下安卓&#xff0c;在弹出的输入框中查看设置&#xff0c;设置一下对应的languages即可&#xff1a; 在苹果模拟器中&#xff0c;跟苹果手机一样&#xff0c;打…

树莓派本地快速搭建web服务器,并发布公网访问

文章目录 树莓派本地快速搭建web服务器&#xff0c;并发布公网访问 树莓派本地快速搭建web服务器&#xff0c;并发布公网访问 随着科技的发展&#xff0c;电子工业也在不断进步&#xff0c;我们身边的电子设备也在朝着小型化和多功能化演进&#xff0c;以往体积庞大的电脑也在…

Selenium多浏览器处理

Python 版本 #导入依赖 import os from selenium import webdriverdef test_browser():#使用os模块的getenv方法来获取声明环境变量browserbrowser os.getenv("browser").lower()#判断browser的值if browser "headless":driver webdriver.PhantomJS()e…

为Android构建现代应用——应用架构

选择风格(Choosing a style) 我们将依照Google在《应用架构指南》中推荐的最佳实践和架构指南来构建OrderNow的架构。 这些定义包括通过各层定义组件的一些Clean Architecture原则。 层次的定义(Definition of the layers) 在应用程序中&#xff0c;我们将定义以下主要层次…

小程序创建

1&#xff0c;下载HBuilder X ;(3.8.7) HBuilderX-高效极客技巧 2,下载模板&#xff08;不选云服务的&#xff09;&#xff1b; 3&#xff0c;运行-运行到小程序模拟器&#xff1b; 4&#xff0c;安装小程序开发工具&#xff1b; 5&#xff0c;选择稳定版-windows64版&…

SpringBoot 统⼀功能处理

目录 前言 1.⽤户登录权限效验 1.1、最初⽤户登录效验 1.2、Spring AOP ⽤户统⼀登录验证的问题 1.3、Spring 拦截器 了解 创建一个 Spring 拦截器 的流程 1、 创建自定义拦截器&#xff0c;实现 HandlerInterceptor 接⼝的preHandle&#xff08;执⾏具体⽅法之前的预处理…

win10日程怎么同步到安卓手机?电脑日程同步到手机方法

在如今快节奏的生活中&#xff0c;高效地管理时间变得至关重要。而对于那些经常在电脑上安排日程的人来说&#xff0c;将这些重要的事务同步到手机上成为了一个迫切的需求。因为目前国内使用win10系统电脑、安卓手机的用户较多&#xff0c;所以越来越多的职场人士想要知道&…

Jenkins 安装构建

一、CentOS 安装 1. 使用该存储库 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key 2. 安装 Java yum install fontconfig java-11-openjdk配…

解决eclipse 打开报错 An error has occurred. See the log file null.

解决eclipse 打开报错an error has ocurred. See the log file null 出现原因&#xff1a;安装了高版本的jdk,更换 jdk 版本&#xff0c;版本太高了。 解决方案&#xff1a;更改环境变量 改成 jkd 1.8

【深度学习实践】垃圾检测

简介 本项目使用深度学习目标检测开源框架PaddleDetection中的yolox算法实现了垃圾检测&#xff0c;本文包含了从头训练yolox模型和直接使用训练好的模型进行推理的代码及相关权重。 一、数据集准备 本次训练的数据集为coco格式&#xff0c;共包含150张垃圾的照片&#xff0…

利用小波分解信号,再重构

function [ output_args ] example4_5( input_args ) %EXAMPLE4_5 Summary of this function goes here % Detailed explanation goes here clc; clear; load leleccum; s leleccum(1:3920); % 进行3层小波分解&#xff0c;小波基函数为db2 [c,l] wavedec(s,3,db2); %进行…

hcip——路由策略

要求&#xff1a; 基础配置 AR1 [R1]int g 0/0/0 [R1-GigabitEthernet0/0/0]ip add 12.0.0.1 24[R1-GigabitEthernet0/0/0]int g 0/0/1 [R1-GigabitEthernet0/0/1]ip add 14.0.0.1 24[R1]int loop0 [R1-LoopBack0]ip add 1.1.1.1 24[R1]rip 1 [R1-rip-1]vers 2 [R1-rip-1]net…

Unity 性能优化五:渲染模块压力

CPU压力 Batching 在GPU渲染前&#xff0c;CPU会把数据按batch发送给GPU&#xff0c;每发送一次&#xff0c;都是一个drawcall&#xff0c;GPU在渲染每个batch的时候&#xff0c;会切换渲染状态&#xff0c;这里的渲染状态指的是&#xff1a;影响对象在屏幕上的外观的渲染属性…

深入学习java虚拟机||JVM内存结构五大模型

目录 程序计数器 栈 虚拟机栈 垃圾回收是否涉及栈内存&#xff1f; 栈内存分配越大越好吗&#xff1f; 方法内的局部变量是否线程安全&#xff1f; 栈内存溢出 本地方法栈 堆 方法区 先看内存图总览 程序计数器 定义&#xff1a;全称P r o g r a m C o u n t e r R e …

windows下配置vue开发环境

安装nodejs&#xff0c;配置npm 1.下载安装包&#xff1a;下载地址&#xff1a;https://nodejs.org/en/download 2.安装node&#xff1a;下载完成后进行安装&#xff0c;记住安装的文件夹。本人安装路径为 D:\Program Files\nodejs 3.配置环境变量&#xff1a; ①安装完成后…

基于传统检测算法hog+svm实现图像多分类

直接上效果图&#xff1a; 代码仓库和视频演示b站视频005期&#xff1a; 到此一游7758258的个人空间-到此一游7758258个人主页-哔哩哔哩视频 代码展示&#xff1a; 数据集在datasets文件夹下 运行01train.py即可训练 训练结束后会保存模型在本地 运行02pyqt.py会有一个可视化…

某信用中心之加速乐实战分析

某信用中心之加速乐实战分析 某信用中心之加速乐实战分析声明逆向目标逆向分析第一层cookie获取第二层cookie获取调试分析JS文件 模拟执行致谢 某信用中心之加速乐实战分析 声明 本文章中所有内容仅供学习交流&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#x…

QTday2信号和槽

点击登录按钮,关闭Widget登录窗口,打开QQList窗口 widget.cpp #include "widget.h"void my_setupUI(Widget *w);Widget::Widget(QWidget *parent): QWidget(parent) {my_setupUI(this); }Widget::~Widget() { }void Widget::login_slots() {//fixemit jump_signal(…

CAN学习笔记1:计算机网络

计算机网络 1 概述 计算机网络就是把多种形式的计算机用通信线路连接起来&#xff0c;并使其能够互相进行交换的系统。实际上&#xff0c;计算机网络包括了计算机、各种硬件、各种软件、组成网络的体系结构、网络传输介质和网络通信计数。因此&#xff0c;计算机网络是计算机…