容斥原理 训练笔记

news2024/9/28 7:24:01

容斥原理

设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.coloradmin.cn/o/808900.html

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

相关文章

简单说说SAP系统中BASIS这个Package

1. 简介 BASIS是SAP系统中非常基础的一个包&#xff0c;属于SAP_BASIS这个模块&#xff0c;这个模块其实也代表着SAP Netweaver的版本&#xff0c;通常而言&#xff0c;SAP_BASIS的版本越高&#xff0c;其所支持的功能也越丰富&#xff0c;例如功能更丰富的ABAP语法&#xff0…

UE4 unlua学习笔记

将这三个插件放入Plugins内并重新编译 创建一个BlueprintLibrary&#xff0c;声明一个全局函数 在这里声明路径 点击Create Lua Template 在Content的Script即可生成对应的lua文件打开它&#xff01; 显示以上lua代码 打印Hello Unlua 创建该UI&#xff0c;就会在创建UI的Con…

数值分析第五章节 用Python实现解线性方程组的直接解法

参考书籍&#xff1a;数值分析 第五版 李庆杨 王能超 易大义编 第5章 解线性方程组的直接解法 文章声明&#xff1a;如有发现错误&#xff0c;欢迎批评指正 文章目录 引言与预备知识高斯消去法列主元消去法 矩阵三角分解法杜利特尔分解法平方根法 向量和矩阵的范数误差分析 引言…

剑指offer42.连续子数组的最大和

这道题挺简单的&#xff0c;看完题脑子里出现的想法就是用一个sum来把数组从前往后加&#xff0c;如果sum小于0&#xff0c;那么对于和来说是会减小的&#xff0c;所以这个时候直接把sum归零&#xff0c;然后从这个位置再往后加&#xff0c;用一个max_sum来记录sum的最大值&…

全面适配 | 走近openGauss数据库+鲲鹏欧拉操作系统

引入 全面适配 | openEuler操作系统 openGauss数据库 开篇 1、openEuler欧拉操作系统 百度百科&#xff1a;openEuler是覆盖全场景的创新平台&#xff0c;在引领内核创新&#xff0c;夯实云化基座的基础上&#xff0c;面向计算架构互联总线、存储介质发展新趋势&#xff0c;…

【LeetCode】剑指 Offer Ⅱ 第1章:整数(5道题) -- Java Version

题库链接&#xff1a;https://leetcode.cn/problem-list/e8X3pBZi/ 题目解决方案剑指 Offer II 001. 整数除法快速除 ⭐剑指 Offer II 002. 二进制加法模拟&#xff1a;StringBuilder ⭐剑指 Offer II 003. 前 n 个数字二进制中 1 的个数动规&#xff1a;res[i] res[i & (…

路由的配置

1、在router中设置路由导航跳转函数,在index.js文件中写这句话&#xff1a; 1.1 只要发生跳转, 就会调用这个函数&#xff1a; 1.2 导航的声明函数 2、访问系统访问控制系统如何形成 3、来一个导航守卫的案例&#xff1a;看看导航守卫的案例&#xff0c;写一个Main.Vue 和login…

【微软知识】微软相关技术知识分享

微软技术领域 一、微软操作系统&#xff1a; 微软的操作系统主要是 Windows 系列&#xff0c;包括 Windows 10、Windows Server 等。了解 Windows 操作系统的基本使用、配置和故障排除是非常重要的。微软操作系统&#xff08;Microsoft System&#xff09;是美国微软开发的Wi…

中文LLaMA模型和指令精调的Alpaca大模型:中文数据进行二次预训练,进一步提升了中文基础语义理解能力

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

Pytorch个人学习记录总结 10

目录 优化器 优化器 官方文档地址&#xff1a;torch.optimhttps://pytorch.org/docs/stable/optim.html Debug过程中查看的grad所在的位置&#xff1a; model --> Protected Atributes --> _modules --> ‘model’ --> Protected Atributes --> _modules -…

Linux学成之路(基础篇0(二十三)MySQL服务(主从MySQL服务和读写分离——补充)

目录 一、MySQL Replication概述 优点 异步复制&#xff08;Asynchronous repication&#xff09; 全同步复制&#xff08;Fully synchronous replication&#xff09; 半同步复制&#xff08;Semisynchronous replication&#xff09; 三、MySQL支持的复制 四、部署主从…

解决AttributeError: ‘DataParallel‘ object has no attribute ‘xxxx_fc1‘

问题描述 训练模型时&#xff0c;分阶段训练&#xff0c;第二阶段加载第一阶段训练好的模型的参数&#xff0c;接着训练 第一阶段训练&#xff0c;含有代码 if (train_on_gpu):if torch.cuda.device_count() > 1:net nn.DataParallel(net)net net.to(device)第二阶段训练…

WIZnet W5100S-EVB-Pico DHCP 配置教程(三)

DHCP协议介绍 什么是DHCP&#xff1f; 动态主机配置协议DHCP&#xff08;Dynamic Host Configuration Protocol&#xff09;是一种网络管理协议&#xff0c;用于集中对用户IP地址进行动态管理和配置。 DHCP于1993年10月成为标准协议&#xff0c;其前身是BOOTP协议。DHCP协议由…

【计算机网络】第 4 课 - 物理层

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、物理层的基本概念 2、物理层协议的主要任务 3、物理层任务 4、总结 1、物理层的基本概念 在计算机网络中&#xff0c;用来…

❤️创意网页:创意动态画布~缤纷移动涂鸦~图片彩色打码

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

【C/C++】#include<xxx.h>和#include“xxx.h“

2023年7月29日&#xff0c;周六晚上 今天下午和晚上花了不少时间去研究这个C/C的头文件以及#include<xxx.h>和#include"xxx.h"之间的区别&#xff0c;收获到了很多的很有用的知识。非常值得花时间来以博客的形式总结这些学习成果。 说实话&#xff0c;我挺想…

使用WGCLOUD监测安卓(Android)设备的运行状态

WGCLOUD是一款开源运维监控软件&#xff0c;除了能监控各种服务器、主机、进程应用、端口、接口、docker容器、日志、数据等资源 WGCLOUD还可以监测安卓设备&#xff0c;比如安卓手机、安卓设备等 我们只要下载对应的安卓客户端&#xff0c;部署运行即可&#xff0c;如下是下…

【Python】数据分析+数据挖掘——探索Pandas中的数据筛选

1. 前言 当涉及数据处理和分析时&#xff0c;Pandas是Python编程语言中最强大、灵活且广泛使用的工具之一。Pandas提供了丰富的功能和方法&#xff0c;使得数据的选择、筛选和处理变得简单而高效。在本博客中&#xff0c;我们将重点介绍Pandas中数据筛选的关键知识点&#xff…

x86架构ubuntu22用docker部署zsnes

0. 环境 x86 ubuntu22 1. 安装docker $ sudo apt remove docker docker-engine docker $ sudo apt update $ sudo apt install -y apt-transport-https ca-certificates curl software-properties-common$ curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg …

HiveSQL SparkSQL中常用知识点记录

目录 0. 相关文章链接 1. hive中多表full join主键重复问题 2. Hive中选出最新一个分区中新增和变化的数据 3. Hive中使用sort_array函数解决collet_list列表排序混乱问题 4. SQL中对小数位数很多的数值转换成文本的时候不使用科学计数法 5. HiveSQL & SparkSQL中炸裂…