(浙江金华)Day 1 组合数计数

Day 1 组合计数

目录

1.组合数

(1)、C(n,m) 读作n选m,二项式系数 :



(2)、n个东西里选m个的方案数 不关心选的顺序:



(3)、二项式系数--->多项式系数:

(x+y+z)^n

2.组合数计算

(1)、递归、纯相加、带初始值的公式(递推:考虑选不选最后一个元素):

(2)、初值(O(n^2)预处理):

(3)、运算(复杂度O(n)):


可以保证每一步运算都是整数;
保证单次O(n)计算组合数模任意数;
可以记录组合数因子出现次数cnt(x);
若知道每个数x的最小质因子mnp(x),从后往前扫 对于每个合数 将cnt(x/mnp(x))+=cnt(x) cnt(mnp(x))+=cnt(x),最后可以得到质因数分解形式 由于质数个数O(n/ln(n)) 。

优化:(对于质数 可以O(n)预处理 O(1)求值 , N>INF, Lucas定理 注意模数必须是质数)

对于非负整数m, n和素数p,下面的同余关系成立:

Ⅰ.如果模数也很大(n,m <= 1e9,P = 1e9+7)就分块打表,为了快速获得x!(x的阶乘),设置B 打表B! (2B)! (3B)! …每次查询一个x!,只需要用表中最接近的值O(B)计算,表的长度O(P/B)

Ⅱ.如果模数不是定值,以后再说.......

3.组合数求前缀和

(1)、过程大致如下:

可以化简为:(S无法快速计算 但是可以递推)

多组询问的情况下可以使用莫队算法,也可以分块预处理出所有m是B的倍数的S

4.组合数组合意义

(1)、概念:

①共有种方式从n元素中选取k项;
②共有种方式从一个n元素中选取(容许重复选取)k元素建立多重集;
③共有个字符串包含k个1和n个0;
④共有个字符串包含k个1和n个0,且没有两个1相邻;
⑤卡特兰数是:

(2)、组合意义:

将n个可区分的元素放进r个可区分的容器里 第i个容器中放了k_i个的方案数

(3)、性质:

一个没:
对称性:

(4)、例题:

例1:一个网格纸 每次只能往右或往上走

只向右或向上走的方案数为:C(n+m,m)或 C(n+m,n);
证明:

例2:
计算方程的整数解个数 一共有M个未知数要满足:
则:解的数量为C(N+M-1,M-1) (插板法).如果未知数有下限,直接将N减掉下限的和

5.组合数例题

例1:

一个正n边形 将其所有对角线连起来 一共有多少个交点(保证n是奇数 不存在三条对角线共点)。
∵4个点确定一个交点   ∴C(n,4) .

例2([AGC001E] BBQ Hard):

烧烤硬 问题陈述:

史努克正在举行另一场烧烤聚会。 这次,他要做一份烤串饭。他有一堆烤串饭盒。第i-th串肉套餐包含一个串,Ai片牛肉和Bi片青椒。这些包装里的所有串都是不同的,可以区分,而所有的牛肉片和青椒片,分别是不能区分的。为了做一顿串肉饭,他从他的串肉饭包里挑了两个,然后从选择的包里拿出所有的东西,也就是两个串和一些牛肉或青椒。(剩下的烤串套餐将不使用。)然后,所有的食物碎片都以任意顺序,一个一个地串在两根烤肉串上。

他可以用多少种不同的方法做一顿烤串饭?当且仅当所使用的串组不同或食物的顺序不同时,制作串餐的两种方法是不同的。因为这个数可以非常大,所以求它的模1e9+7。

问题简化:
给定a,b数组,要求下面式子模1000000007:

思路:
考虑把组合数描述成坐标。 那么这就是(−ai,−bi)到(aj,bj) ,中途只能向上或向左走的路径条数。 考虑在坐标系上点上所有点,直接来一波dp算方案:

	f[i][j]=f[i][j]+f[i−1][j]+f[i][j−1];

如果本来就有一个点就初始化那个点为1。考虑这样算算重了自己的三象限坐标到自己一象限坐标的方案,所以要减去自己到自己的方案。 也就是说直接拿自己的组合数去减即可.

代码实现:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=2e5+10;
const int M=2e3+10;

int n;
int a[N],b[N],f[M*2+1][M*2+1];
ll p[N],e[N],c[N];
ll ans;

inline int read() {
	int n=0,f=1;char ch=getchar();
	while (ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while (ch<='9' && ch>= '0') {n=(n<<3)+(n<<1)+ch-'0';ch=getchar();}
	return n*f;
}

inline ll C(ll x,ll y) {
	if(x<y) return 0;
	if(x==y || !y) return 1;
	return e[x]*c[y]%mod*c[x-y]%mod;
}

int main() {
	n=read();
	e[0]=p[1]=c[1]=c[0]=1,ans=0;
	for(int i=1;i<=(M<<2)+100;++i) e[i]=e[i-1]*i%mod;	
	for(int i=2;i<=(M<<2)+100;++i) {
		p[i]=(mod-(mod/i))*p[mod%i]%mod;
		c[i]=c[i-1]*p[i]%mod;	
	}
	for(int i=1;i<=n;++i) {
		a[i]=read(),b[i]=read();
		f[M-a[i]][M-b[i]]++;
        ans=(ans-C(a[i]*2+b[i]*2,a[i]*2)%mod+mod)%mod;
	}
	for(int i=1;i<=(M<<1);++i) {
		for(int j=1;j<=(M<<1);++j) {
			f[i][j]=(f[i][j]+f[i-1][j])%mod;
			f[i][j]=(f[i][j]+f[i][j-1])%mod;
		}
	}
    for(int i=1;i<=n;++i) ans=(ans+f[a[i]+M][b[i]+M])%mod;
	printf("%I64d\n",ans*p[2]%mod);
    return 0;
}
/*
3
1 1
1 1
2 1

26
*/

例3:
问题描述:
给你一棵n个节点的有根树。你要给每个节点分配一个1~n的数字,使得每个节点分配的数字不同,并且每个节点分配的数字都是它子树内最小的,求方案数。
考虑树形dp,dp(i)表示i这个子树分配1~sz(i)的方案数,转移:
进一步推理可得:

6.基础组合问题

(1)、基础概念:

①.加法原理 要么A 要么B A和B不相交,一个整数可以属于[1,3]或[4,6] 那么共有6种可能

②.乘法原理 AxB A和B中各选一个,第一个整数属于[1,3] 第二个整数属于[1,2] 共有6种可能.

③.n个可区分的元素选k个排成一列 排列方法有n(n-1)(n-2)…(n-k+1)=n!/(n-k)!种.

(2)、例题:

题目描述:
n个未知数,给定每个数的上限a_i,问你有多少种方法使得这些未知数都是正整数且互不相同。输出方案数模1e9+7。(n<=1e5 1<=a_i<=1e9 30)
思路:

	考虑将a_i从小到大排序 依次确定未知数的值
	ANS=a_1*(a_2-1)*(a_3-2)*…*(a_n-(n-1))

(3)、一个很有用的计数原则:

一个由计数对象组成的集合S,要计算它的大小|S|,考虑如果我们找到一个集合T,使得S的元素与T的元素一一对应,那么|S|=|T|

(4)、一个推广:

如果S的每个元素对应到a个T中的元素,T的每个元素对应到b个S中的元素,那么有:
a|S|=b|T| |S|=|T|*b/a

(5)、例题:

题目描述:
n个可区分的元素围成一排 有多少种方案?

思路:

	S:n个元素的环排列        T:n个元素的排列
	S->T:对于一个环排列 将其旋转 可以得到n个不同的排列 即对应到T中的n个元素
	T->S:对于一个排列 只能被一个环排列旋转得到
	n|S|=|T|    |S|=|T|/n

7.Twelvefold way && 容斥原理

(1)、Twelvefold way 描述:

n个有标号/无标号的球分给m个有标号/无标号;盒子有三种限制:

A)无限制
B)每个盒子至少有一个球
C)每个盒子至多有一个球

共12种问题:
为了方便 将有标号记为L(labelled) 无标号记为U(unlabelled) 那么一个问题可以用缩写代替

(2)、Twelvefold way(①~⑦)

①(LLA)n个有标号的球分给m个有标号的盒子(m^n)

②(ULA)n个无标号的球分给m个有标号的盒子,等同于方程的整数解个数 C(n+m-1,m-1)

③(ULB)n个无标号的球分给m个有标号的盒子没有空盒,等同于方程整数解个数 C(n-1,m-1)

④(LLC)n个有标号的球分给m个有标号的盒子 每个盒子至多放一个球(m!/(m-n)!)

⑤(ULC)n个无标号的球分给m个有标号的盒子 每个盒子至多放一个球C(m,n)

⑥(LUC)n个有标号的球分给m个无标号的盒子 每个盒子至多放一个球[n<=m]

⑦(UUC) n个无标号的球分给m个无标号的盒子 每个盒子至多放一个球[n<=m]

(3)、容斥原理

①.基础:



②.容斥原理基础应用(例题):
1~100中既不被2整除也不被3整除也不被5整除的数有多少个?

A=被2整除的数的集合   
B=被3整除的数的集合
C=被5整除的数的集合


∴|A∪B∪C|=50+33+20-16-10-6+3=74 ∴100-74=26

(4)、Twelvefold way(⑧~⑨)

⑧(LLB)n个有标号的球划分给m个有标号的盒子 不能有空盒

⑨(LUB) n个有标号的球划分给m个无标号的盒子 不能有空盒

8.Twelvefold way && 第二类斯特林数

(1)、第二类斯特林数简介:

就以(LUB)和(LLB)为例来简单说一下吧:
(LUB) 即n个有标号的球划分给m个无标号的盒子不能有空盒,(LLB) S(n,k)k!

(2)、递推式(考虑最后一个球是否独立给一个盒子):


(3)、Twelvefold way (⑩)

(LUA)n个有标号的球划分给m个无标号的盒子,枚举有几个盒子被分配了

S(n,0)+S(n,1)+…+S(n,m)

9.Twelvefold way && 划分数

(1)、划分数(p(n,k))基础知识:

① n=x_1+x_2+…+x_k,将n划分为k个正整数的方案数 方案与x的顺序无关
② 递推式:p(n,k)=p(n-k,k)+p(n-1,k-1) (考虑最小的数是否为1)

(2)、Twelvefold way(最后两个)

11.(UUB)n个无标号的球划分给m个无标号的盒子 每个盒子至少有一个球 p(n,m)

12.(UUA)n个无标号的球划分给m个无标号的盒子,枚举有几个盒子被分配了,p(n,1)+p(n,2)+…+p(n,m) ,p(n+m,m).

(3)、Twelvefold way(完结篇)


(PS:这里的p_k(n) 定义为至多划分为k个的划分数)

14.卡特兰数

(1)、基础:


①.1,1,2,5,14,42,132,429,1430…

②.组合应用:
有2n个括号的合法括号序列个数(递推式相同)
如:C(3)=5 ((())) ()(()) ()()() (())() (()())

③.有n个非叶子节点的满二叉树的个数

④.不超过对角线的NE 网格路径的个数(或算不经过y=x+1这条直线的路径个数),具体来说,就是考虑碰到了这条直线的路径,我们将其之前的路径按照这条直线对称,那么可以对应到一个(-1,1)到(n,n)的路径, 又由于每个(-1,1)到(n,n)的路径都必然经过y=x+1这条直线,所以可以对应到一个(0,0)到(n,n)且碰到了y=x+1这条直线的路径;由之前提到的计数原则得到:(0,0)到(n,n)且碰到了y=x+1的路径条数与(-1,1)到(n,n)的路径条数相等,

15.容斥原理进阶 && 容斥原理进阶练习

(1)、容斥原理可以与之前提到计数方法结合:

给定上界和下界的方程的整数解问题
下界可以直接从N减掉,不满足X<=B  X>=B+1,考虑容斥一个子集不满足上界后,所有变量只剩下界,可 以 直 接 组 合 数 计 算 方 案 数,由于最后方案数只和被减掉多少以及容斥系数有关,当未知数个数多但是上界小的时候,可以使用类似背包的动态规划优化.

(2)、例题:

例1:
题目描述:
问你有多少个n位数,满足以下要求:

1)这个数是回文串
2)奇数位的和等于偶数位的和

输出答案模1e9+7,n<=1e6

思路:
Ⅰ、位数是偶数 答案为10^(n/2);
Ⅱ、位数是奇数:

	解:设 abcdcba    
		则有:2a+2c=2b+d;
		每个未知数的范围为[0,9].
		移项后 得到:2x_1+2x_2+2x_3+….-2y_1-2y_2-2y_3-…-z=0
		设有k1个正项 k2个负项
		所有未知数的范围为[0,9]
		首先z可以枚举
		发现负项的取值范围为 [-9,0] 不妨将每个负项加9
		这样式子就变成了
		2x_1+2x_2+2x_3+…+2(9-y_1)+2(9-y_2)+…-z=18k2
		此时除了z外所有未知数是等价的
		问题就变成了 有k1+k2个值域在[0,9]的未知数 问他们的和为S有多少种方案
		发现这是一个有上界的方程的整数解的问题
		可以O(k1+k2)(即O(n))枚举有几个数大于上界
		最终复杂度O(10n)

例2:
题目描述:
给定n个障碍点(x_i,y_i) 求有多少条不经过障碍点的(0,0)到(X,Y)的NE 网格路径(n<=5000 0<=x_i,y_i,X,Y<=100000)。

思路:
dp(i)表示从(0,0)到(x_i,y_i)不经过除了终点外的障碍点的方案数

转移:枚举第一个碰到的障碍点将终点视为第n+1个障碍点 那么答案为dp(n+1)(PS:注意转移不会成环)

例3:
问题描述:
n种珠子,第i种有a_i个。将它们排成一列,要求相邻的两个珠子种类不同,问有多少种方案。

思路:

解:设S=a_1+a_2+…+a_n
	原题条件:所有S-1对相邻的珠子种类不同难以直接容斥
	转化:考虑某一种类的所有a_i个珠子 a_i-1对相对位置上相邻的珠子不相邻 
	对于某一种类 容斥后变为某些相对位置上相邻的珠子相邻 即这些珠子连成一段
	不妨将这些珠子看做一个整体 那么我们可以把段数相同的情况合并 记录段数一定时 容斥系数的和记容斥后剩余x段的容斥系数的和为s_x
	考虑如何计算对整体容斥的贡献
	x段珠子与x个珠子在对排列方案数的贡献是相同的
	每一类相当于变成:若看做1个珠子时 贡献系数为s_1 看做2个珠子时 贡献系数为s_2 …
	总答案就是 枚举每类珠子被看做了几个珠子 计算排列成一列的方案数 将方案数乘上贡献系数s的积加入答案
	可以使用类似背包的dp

例4:
问题描述:
n个不同的正整数排成一个序列,其中数字i出现次数为ci。对于每一个这样的序列,定义他的权值如下:
Ⅰ、将这个序列首尾相接放在一个圆上。把这些数字分成若干相邻的段,使得每段里都是在圆上相邻的数字,任意两段没有公共的元素,每一段中的数字都相同,相邻段中的数字不同。这个序列的权值定义为所有段的长度之积。求所有序列的权值和对1000000007取膜。(PS:虽然计算序列权值的时候是圆排列,但互为循环排列的不同序列仍然认为是不同的,如(1,2,1,2)和(2,1,2,1)就认为是不同的序列

思路:

	解:
		先考虑序列上的问题,用之前介绍的方法做即可。
		不同的是 我们不仅需要考虑容斥系数 还要考虑段的权值
		可以使用dp计算出段数一定时 容斥系数乘权值的和 作为贡献系数
		后面与之前介绍的方法完全一样
		考虑如何处理环的问题
		注意这题序列的开头与结尾如果数字相同 也视为同一段
		可以考虑使用之前说的计数原则:
		S:本题中描述的序列(代表一个环)包含d段数字1 
		T:一个开头为数字1,结尾不为数字1的序列 包含d段数字1 
		T->S:旋转n次,共对应到n个S中的元素
		S->T:一共被d个T中的元素旋转到
		所以得到n|T|=d|S|   |S|=|T|*n/d
		所以得到n|T|=d|S|   |S|=|T|*n/d
		由于我们计算的是T的集合里所有元素的代价和
		并且S和T的对应关系并不会改变代价
		所以我们只要算出所有T的元素的代价除以d(即数字1的段数)的和,再乘上n就可以得到S中所有元素的代价和,即最终答案

16.小练习(未完结...)

(1)、AGC018E

题目描述:
给定三个不相交的矩形A(X1,Y1)-(X2,Y2) B(X3,Y3)-(X4,Y4) C(X5,Y5)-(X6,Y6),求有多少条NE lattice path从A中某个点出发 中途经过选定的B中的某个点 最终到达C中的某个点,ABC中选定的点不同 lattice path也视为不同( 1<=X1<=X2<X3<=X4<X5<=X6<=1000000).

(2)、某个题1:

题目描述:
飞机上有n个座位排成一列,共有m个乘客。你需要为每个乘客选定一个座位以及进入飞机的入口(要么从前门进 要么从后门进) 每个人会从指定的入口走向指定的座位,如果座位已经被占了,他就会继续向前走直到一个没有被占的座位,并占据那个座位。如果他直到飞机的一端都没有找到空座位,他就会生气。求有多少种分配的方案,使得没有人会生气。输出方案模1e9+7(n,m<=1e6).

(3)、某个题2:

题目描述:
一共n+m个判断题,告诉你答案有n个YES m个NO。现在这n+m个题以随机的顺序依次给你,每道题你回答后就会告诉你答案是否正确。你使用最优策略回答问题。求期望你答对的题数。输出答案模1e9+7(n,m<=1e6).

posted @ 2018-10-09 20:21  倚栏听风v  阅读(631)  评论(0编辑  收藏  举报