二项式反演

二项式反演

在很多情况下,“恰好”往往是不好求的,因为恰好意味着" ≤ \leq "并且" ≥ \geq ",需要进行很多限制,破坏了情况之间的独立性。

二项式反演则通过一定手段,使得限制" ≤ \leq "与" ≥ \geq "中只保留一个,使得情况独立,便于处理。

二项式定理:
在这里插入图片描述

推论:
在这里插入图片描述

二项式反演公式:
在这里插入图片描述
证明一下:
只证明左边到右边。仿照证明过程容易证明右边到左边。

在这里插入图片描述

注意到若 j > i j>i j>i,则 ( j i ) = 0 (^i_j)=0 (ji)=0,可扩大枚举范围:
在这里插入图片描述

当然这里有一个非常有意思的地方就是,一些地方的证明中有如下过程:
∑ i = 0 k ∑ j = 0 i = ∑ j = 0 k ∑ i = 0 j \overset{k}{\underset {i=0}\sum}\overset{i}{\underset {j=0}\sum}=\overset{k}{\underset {j=0}\sum}\overset{j}{\underset {i=0}\sum} i=0kj=0i=j=0ki=0j

这是在描述,把被和式求值的部分看做一个三角矩阵,左边是先对行求和,右边是先对列求和。

QED.

恰好->至多型

若对于一个问题,其限制条件为简单的数字形式,但是其细分是本质不同的,例如“恰好有两组成功配对的方案数”、“恰好有3人收到了礼物”,则这个条件可以根据加法细分。例如“两组”可以分为一组(A,B)、两组(AB),3人可以分为1人(A,B,C)、2人(AB,BC,AC)、3人(ABC)。

g ( k ) g(k) g(k)表示恰好满足条件的方案数, f ( k ) f(k) f(k)表示至多满足条件的方案数,其中需要 f f f是好求的。

则广泛存在一种关系:
在这里插入图片描述
这是由于,对于 g ( i ) g(i) g(i)而言,由于条件k是可分的,只需要从条件 k k k中分出 i i i份,就可以使得条件满足,而由于分出来的条件是本质不同的(例如满足收礼物是一个人,但收到礼物的可以是A,B或者C),因此一个 g ( i ) g(i) g(i) f ( k ) f(k) f(k)贡献的次数就是 ( k i ) \begin{pmatrix}k\\ i\end{pmatrix} (ki)

则可以反演求出 g g g
在这里插入图片描述

因此两类二项式反演都要满足两个条件:

  • 限制条件可分
  • 分为相同值的限制条件本质不同

错位排列

f ( i ) f(i) f(i)表示至多有i位置排错的方案数, g ( i ) g(i) g(i)表示恰好有i个位置排错的方案数。

显然“i”可分,有n个位置,就会有n-1个位置,n-2个位置…,显然分出来的"位置"本质不同,例如两个位置,可以是前两个位置,也可以是第1、第3个位置。

则有:
在这里插入图片描述

因而有:
在这里插入图片描述
注意到 f ( i ) f(i) f(i)是非常好求的,因为至多有 i i i个位置排错就相当于全排列。即 f ( i ) = i ! f(i)=i! f(i)=i!

因此就可以了。

#include<iostream>
using namespace std;
long long p[25];
int n;
int main() {
	p[0]=1;
	for(int i=1;i<=20;i++) p[i]=p[i-1]*i;
	cin>>n;
	long long ans=0;
	for(int i=0;i<=n;i++)
		ans+=p[n]/p[i]*(i&1?-1:1);
	cout<<ans;
	return 0;
}
实现上对式子做了一些变换

UVALive 7040

题意简述,有一排n个格子,m种颜色,涂满颜色,使得相邻格子颜色不同,并且每一种颜色(都就是恰好嘛)用到,统计方案数。
1 ≤ n ≤ 1 0 9 , 1 ≤ m ≤ 1 0 6 1\leq n\leq 10^9,1\leq m\leq 10^6 1n109,1m106

每一种颜色都用到,显然是很不好求的。一种显然的做法是首先强制每种颜色用一次,然后把这些强制的位置插进格子里,做全排列,不过显然这样会有重复情况,所以这种做法假了,所以我们用二项式反演让它变得好求。

f ( i ) f(i) f(i)表示至多用i种颜色的方案数, g ( i ) g(i) g(i)表示恰好用i种颜色的方案数。
显然"i种颜色"可分,显然分的"颜色"本质不同,比如两种颜色,可以是红蓝,也可以是绿蓝、黄蓝。

我们注意到,根据组合容易求出 f ( i ) = i ( i − 1 ) n − 1 f(i)=i(i-1)^{n-1} f(i)=i(i1)n1。反演求出 g g g即可。

分特产

题目所说同一种的特产是无标号的,人是有标号的。

显然“每个人至少一件”是非常不好求的,因为这样每种特产之间就不独立了。我们先考虑可以 有人 没有,这样就不会互相影响了。

可以 有人 没有的方案数是非常好求的,设目前有 i i i个人,特产用 a a a表示,则方案数就是:
在这里插入图片描述
这是因为,我们意识到每一种特产之间是相互独立的,考虑第 j j j种特产分为 i i i份,就相当于把 a j a_j aj个相同元素放到 i i i个可空集合的方案数,对应方程 ∑ k = 1 i x k = a j \overset{i}{\underset{k=1}\sum}x_k=a_j k=1ixk=aj的非负整数解的个数。

f ( i ) f(i) f(i)表示至多有 i i i个人分到至少一份特产的方案数, g ( i ) g(i) g(i)为恰好有 i i i个人分到至少一份的方案数。
则可以反演。

#include<iostream>
using namespace std;
const int N=1000;
const long long M=1e9+7;
long long a[N+5],C[2*N+5][2*N+5],f[N+5],g[N+5];
int n,m;
int main() {
	cin>>n>>m;
	for(int i=1;i<=m;i++) cin>>a[i];
	for(int i=0;i<=N;i++) C[i][0]=1;
	for(int i=1;i<=2*N;i++)
		for(int j=1;j<=i;j++)
			(C[i][j]=C[i-1][j-1]+C[i-1][j])%=M;
	for(int i=1;i<=n;i++)
		f[i]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			(f[i]*=C[a[j]+i-1][i-1])%=M;
//	for(int i=0;i<=n;i++)
//		cout<<i<<':'<<f[i]<<endl;
	for(int i=0;i<=n;i++)
		(g[n]+=C[n][i]*f[i]*((n-i)&1?-1:1))%=M;
	cout<<(g[n]%M+M)%M;		
}

注意到这里g只用到一项,但是为了视觉效果就不改了。

恰好->至少型(指定答案型)

g ( k ) g(k) g(k)表示恰好满足条件 k k k的方案数, f ( k ) f(k) f(k)表示至少满足条件 k k k的方案数,或者说指定 k k k个位置,使得其满足条件,剩下的位置则不做限制,可以满足条件,也可以不满足。

因此有:
在这里插入图片描述
其中n表示问题的极大上界,也可以说,使得 i > n , g ( i ) = 0 , 即 g ( i ) 无意义 i>n,g(i)=0,即g(i)无意义 i>n,g(i)=0,g(i)无意义

这个公式就是说说,对于满足 i i i个情况来说,只需要从其中任取满足情况的 i i i个中的 k k k个,即可符合 f ( k ) f(k) f(k)的要求,因此在 f ( k ) f(k) f(k)中被贡献了 ( i k ) \begin{pmatrix}i\\ k\end{pmatrix} (ik)次。

具体来说,总共有3个人,设 f ( 1 ) f(1) f(1)表示至少有一个人收到礼物的情况数,我们可以枚举这个人是A,B或C,则ABC都收到礼物的情况,就被统计了三次,AB,BC,AC收到礼物的情况,分别被统计了两次。

则有:
在这里插入图片描述

判定条件也是那两点,对于“i”收到礼物而言,i是可分的,而是有标号的,就满足条件,存在 f f f g g g的二项式反演关系式。

BZOJ2839 集合取数

题意简述:
一个有n个不同元素的集合有2n个不同子集,现在其子集中取出至少一个集合,使得其交集的元素个数恰好为k,求合法方案数。
1 ≤ n ≤ 1 0 6 , 0 ≤ k ≤ n 1\leq n\leq 10^6,0\leq k\leq n 1n106,0kn

我们注意到,设 f ( i ) f(i) f(i)表示交集大小至少为i的方案数,则这是非常好求的, f ( i ) = ( n i ) ( 2 2 n − i − 1 ) f(i)=\begin{pmatrix}n\\ i\end{pmatrix}\left(2^{2^{n-i}}-1\right) f(i)=(ni)(22ni1)。这是因为,含有 i i i个元素的情形有 ( n i ) \begin{pmatrix}n\\ i\end{pmatrix} (ni)种,则含有这i个元素的集合有 2 n − i 2^{n-i} 2ni个,每个集合可选可不选,但不能都不选。

我们设 g ( i ) g(i) g(i)表示交集大小恰好为 i i i(也就是有i交集)的方案数,则我们注意到,i可分,并且交集之间两两不同,也就是有标号,因此构成二项式反演关系。

较为复杂的二项式反演

记题目中的k为K。设糖果为a,药片为b。
我们称 a i > b j a_i>b_j ai>bj为合法情况。

首先注意到若n+K为奇数,则无解。(方案数是0)

然后对于K是偶数的情况,注意到题目中有“恰好”这个意思,因此考虑二项式反演。

f ( i ) f(i) f(i)表示至少有 i i i组a>b的情况数, g ( i ) g(i) g(i)表示恰好有 i i i组a>b的情况数。注意到i是可分的(有i组合法的情况,就会有i-1组合法的情况),并且情况数相同的时候,情况是有不同的,因此可以二项式反演。

接下来求 f ( i ) f(i) f(i),需要一个简单dp的过程,首先把a、b数组升序排序,然后设 F i , j F_{i,j} Fi,j表示前i个a,与全部的b做匹配,至少 j组合法情况的方案数。

首先有不知道是合法还是不合法的匹配, F i , j + = F i , j − 1 F_{i,j}+=F_{i,j-1} Fi,j+=Fi,j1,合法更好,不合法拉倒。换句话说,搁置 a i a_i ai a i a_i ai先不做匹配,等dp到n的位置,确定完了所有合法匹配之后,再做随机匹配。

其次有合法匹配,记b数组中小于 a i a_i ai的有k个, F i , j + = F i − 1 , j − 1 × ( k − ( j − 1 ) ) F_{i,j}+=F_{i-1,j-1}\times (k-(j-1)) Fi,j+=Fi1,j1×(k(j1))。这是因为对于 a i a_i ai而言的合法匹配的区域必然包含原有合法匹配的区域,不能占以前的位置,因此要减去j-1。

考虑边界条件,显然 F i , 0 = 1 F_{i,0}=1 Fi,0=1,这并不是说有0组合法情况的方案数一定只有一种,而是说当从 F i , 0 F_{i,0} Fi,0处转移时,理应获得1的贡献。也可以说我们搁置了 a 1 , . . . , a i a_1,...,a_i a1,...,ai的所有位置,等到dp到n的时候再随机匹配。

注意到 f ( i ) = ( n − i ) ! F n , i f(i)=(n-i)!F_{n,i} f(i)=(ni)!Fn,i,因为有i对合法匹配,剩下的位置被搁置了,随机匹配。

就做完了。

#include<iostream>
#include<algorithm>
using namespace std;
const int N=2000;
const long long M=1e9+9;
int n,K;
long long p[N+5],C[N+5][N+5];
long long f[N+5],F[N+5][N+5];
int a[N+5],b[N+5];
int main() {
	cin>>n>>K;
	if((n+K)&1) {
		cout<<0;
		return 0;
	}
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	for(int i=0;i<=N;i++) C[i][0]=1;
	for(int i=1;i<=N;i++)
		for(int j=1;j<=i;j++)
			(C[i][j]=C[i-1][j-1]+C[i-1][j])%=M;
	sort(a+1,a+1+n);
	sort(b+1,b+1+n);
	for(int i=0;i<=n;i++) F[i][0]=1;
//	cout<<"***";
	for(int i=1;i<=n;i++) {
		long long k=upper_bound(b+1,b+1+n,a[i])-b;
//		cout<<k<<' ';
		for(int j=1;j<=i;j++) 
			(F[i][j]+=F[i-1][j]+F[i-1][j-1]*max((long long)k-j,0ll))%=M;
	}
//	for(int i=1;i<=n;i++,cout<<endl)
//		for(int j=1;j<=i;j++)
//			cout<<F[i][j]<<' '; 
//	cout<<"***";
	p[0]=1;
	for(long long i=1;i<=N;i++)
		(p[i]=i*p[i-1])%=M;
	for(int i=0;i<=n;i++)
		(f[i]=F[n][i]*p[n-i])%=M;
	K=n+K>>1;
	long long g=0;
	for(int i=K;i<=n;i++)
		(((g+=C[i][K]*f[i]*(i-K&1?-1:1))%=M)+=M)%=M;
	cout<<g;
}

后记

于是皆大欢喜。

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

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

相关文章

谷粒商城笔记+踩坑(21)——提交订单。原子性验令牌+锁定库存

目录 1、环境准备 1.1、业务流程 1.2、Controller 层编写下单功能接口 1.3、订单提交的模型类 1.4、前端页面 confirm.html 提供数据 2、提交订单业务完整代码 3、原子性验令牌&#xff1a;令牌的对比和删除保证原子性 4、初始化新订单&#xff0c;包含订单、订单项等信…

C++ : C++基础 :从内存的角度看 char[]和char*

char*和char[]区别1&#xff1a;数据在内存中的存储2&#xff1a;char*和 char[]分析3&#xff1a;char* p2 和 char p1[]3.1 修改指针所指向的地址4: string转char*5: char * 转string5.1 to_string()用法1&#xff1a;数据在内存中的存储 栈&#xff1a;就是在那些由编译器在…

PYQT 自带的 Pyrcc 系统的使用,PyInstaller对PYQT程序进行打包,不能打包背景图片,图标等解决办法

问题 使用 PyInstaller 对程序进行打包&#xff0c;不能打包背景图片。打包后的软件可以正常运行&#xff0c;但涉及到图片相关的资源全部不显示。 问题分析 当使用Python PyInstaller对程序进行打包时&#xff0c;如果程序中涉及到背景图片&#xff0c;会出现无法打包背景图…

第十一章 指针

第十一章 指针 目录一&#xff0e; 指针变量二&#xff0e; 取地址运算符和间接寻址运算符三&#xff0e; 指针赋值一&#xff0e; 指针变量 概述   指针就是地址&#xff0c;而指针变量就是存储地址的变量。指针的大小都是相同的。32位机器一个地址是4个byte。64位机器一个…

【ChatGPT】这是一篇ChatGPT写的关于Python的文章

文章目录Python基础语法教学1、变量2、数据类型3、运算符4、条件语句5、循环语句更高级的概念1、函数2、模块3、面向对象编程ChatGPT的记录Python基础语法教学 Python是一种高级编程语言&#xff0c;它被广泛应用于计算机科学领域、数据分析和人工智能等各种领域。在学习Pytho…

聊聊MyBatis缓存机制(一)

前言 Mybatis是常见的Java数据库访问层框架&#xff0c;虽然我们在日常的开发中一般都是使用Mybatis Plus&#xff0c;但是从官网信息可以知道&#xff0c;其实Mybatis Plus只是让开发者在使用上更简单&#xff0c;并没有改动核心原理。在日常工作中&#xff0c;大多数开发者都…

HTML5 <!DOCTYPE> 标签

实例 <!DOCTYPE> 声明非常重要&#xff0c;它是一种标准通用标记语言的文档类型声明&#xff0c;通过该标签&#xff0c;浏览器能够了解HTML5文档正在使用的HTML规范&#xff0c;<!DOCTYPE> 声明是HTML5文档的起始点&#xff0c;也就是说它必须位于HTML5文档的第一…

《SpringBoot》第03章 自动配置机制(二) 根注解@SpringBootApplication

前言 之前介绍到了把启动类封装成BeanDefinition注入进IOC容器&#xff0c;那么这个启动类就会跟普通的bean一样在refresh()中被实例化&#xff0c;那么显而易见作为启动类这个实例化并不简单&#xff0c;肯定会存在一些特殊处理&#xff0c;那么就需要研究一下其注解SpringBo…

AI只会淘汰不进步的程序员

最近AI界的大新闻有点多&#xff0c;属于多到每天很努力都追不上&#xff0c;每天都忙着体验各种新产品或申请试用新产品。各种自媒体肯定也不会放过这个机会&#xff0c;AI取代程序员的文章是年年有&#xff0c;今天特别多。那么AI到底会不会取代程序员的工作呢&#xff1f;先…

[chapter4][5G-NR][传输方案]

前言&#xff1a; 多天线传输的基本过程传输方案 前面见过数据加扰&#xff0c;调制&#xff0c;层映射的一些基本原理&#xff0c;算法。 这里重点讲一下传输方案 目录&#xff1a; 1&#xff1a; 下行传输方案 2&#xff1a; 上行传输方案 3&#xff1a; 资源块映射 备注&…

.net开发安卓从入门到放弃 最后的挣扎(排查程序闪退问题记录-到目前为止仍在继续)

安卓apk闪退问题排查记录logcat程序包名先看日志&#xff08;以下日志是多次闪退记录的系统日志&#xff0c;挑拣几次有代表性的发上来&#xff09;最近一次闪退adb shell tophelp一个demo说明adb shell dumpsys meminfo <package_name>ps&#xff1a;写在前面&#xff0…

训练中文版chatgpt

文章目录1. 斯坦福的模型——小而低廉&#xff1a;Alpaca: A Strong Open-Source Instruction-Following Model2. Meta 模型&#xff1a;LLaMA&#xff1a;open and efficient foundation language models3.ChatGLM4.斯坦福开源机器人小羊驼Vicuna&#xff0c;130亿参数匹敌90%…

SSM+LayUi实现的学籍管理系统(分为管理员、教师、学生三个角色,实现了专业管理,班级管理,学生管理,老师管理,课程管理,开课管理以及用户管理等)

博客目录jspservletmysql实现的停车场管理系统实现功能截图系统功能使用技术完整源码jspservletmysql实现的停车场管理系统 本系统是一个servlet原生框架实现的停车场管理系统&#xff0c;总共分为两个角色&#xff0c;普通用户和管理员&#xff0c;实现了用户管理、停车信息管…

Linux基础IO

本篇博客来讲述Linux中的新一模块--文件IO&#xff0c;我们来做简单的介绍和陈述。 在笔者之前的文章之中&#xff0c;已经对C语言中的文件操作做了简要介绍&#xff0c;我们旧事重提&#xff0c;再次进行一个简要的回顾。 目录 1.文件的操作 1.1打开文件 1.2向文件写入数…

Java多态

目录 1.多态是什么&#xff1f; 2.多态的条件 3.重写 3.1重写的概念 3.2重写的作用 3.3重写的规则 4.向上转型与向下转型 4.1向上转型 4.2向下转型 5.多态的优缺点 5.1 优点 5.2 缺点 面向对象程序三大特性&#xff1a;封装、继承、多态。 1.多态是什么&#xff1…

七结(4.2)遍历集合与javaFX界面

今天由学长学界们进行了一次授课&#xff0c;算是温习了一遍面向对象的知识&#xff0c;同时配置了关于javaFX的环境&#xff0c;以及一些关于项目的知识。 java学习总结&#xff1a; Collection的遍历&#xff1a; 迭代器遍历&#xff08;Iterator&#xff09;&#xff1a;…

leetcode 87. Scramble String(扰乱字符串)

scramble(字符串s) 算法&#xff1a; s长度为1时结束。 s可以拆分成2部分x和y&#xff0c;sxy, 这两部分可以交换&#xff0c;也可以不交换&#xff0c;即 s xy 或 s yx. 上面scramble还会递归作用于x 和 y. 给出相同长度的字符串s1, s2, 问s2是否可通过scramble(s1)获得。 …

WTW-16P 应用电路

1、WTW-16P 按键控制 PWM 输出应用电路 软件设置&#xff1a; 按键控制模式。 I/O 口定义&#xff1a; 选取 I/O 口 P00、P01、P02、P03 作为触发口&#xff0c;在编辑 WT588D 语音工程时&#xff0c;把触发口的按键定义为可触发播放的触发方式&#xff0c;就可进行工作。 BUS…

如何提高网站安全防护?

网站的安全问题一直是很多运维人员的心头大患&#xff0c;一个网站的安全性如果出现问题&#xff0c;那么后续的一系列潜在危害都会起到连锁反应。就好像网站被挂马&#xff0c;容易遭受恶意请求呀&#xff0c;数据泄露等等都会成为杀死网站的凶手。 1、让服务器有一个安全稳定…

百度双塔召回引擎MOBIUS

1. 概述 对于一个搜索或者推荐系统来说&#xff0c;分阶段的设计都是当下的一个标配&#xff0c;主要是为了平衡效率和效果&#xff0c;在百度的广告系统中&#xff0c;也是分成了如下的三层结构&#xff1a; 最上层的Matching阶段负责从全库中找到与query相关的候选集&#x…