组合数学

[TJOI2015]组合数学

只谈情不闲聊 提交于 2019-12-02 15:39:55
Dilworth定理:最小链覆盖数=最大点独立集 这题要求最小链覆盖,我们可以直接转化为最大独立点集来求 考虑DP 设$f[i][j]$表示当前在位置i,j时的答案,显然$f[i][j]$可以从$f[i-1][j]$和$f[i][j+1]$转移过来(反链),但是如果要是最大独立点集的话要求独立,所以还可以从$f[i-1][j+1]$这个无法到达的地方转移过来 所以有: $$f[i][j]=max\{f[i-1][j],f[i][j+1],f[i-1][j+1]+a[i][j]\}$$ 1 //张家奇怎么又AKIOI了呀,怎么CSP也满分啊...怎么清北天天给他打电话啊...怎么会有这么强的人啊 2 #include<bits/stdc++.h> 3 #define int long long 4 #define writeln(x) write(x),puts("") 5 #define writep(x) write(x),putchar(' ') 6 using namespace std; 7 inline int read(){ 8 int ans=0,f=1;char chr=getchar(); 9 while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();} 10 while(isdigit(chr)){ans=(ans

组合数学入门—TwelveFold Way

两盒软妹~` 提交于 2019-12-01 18:21:01
组合数学入门—TwelveFold Way 你需要解决 \(12\) 个组合计数问题。 \(n\) 个有标号/无标号的球分给 \(m\) 个有标号/无标号的盒子 盒子有三种限制: A、无限制 B、每个盒子至少有一个球 C、每个盒子至多有一个球 共有 \(2\times2\times3=12\) 种问题: 为了方便 将有标号记为L(labelled) 无标号记为U(unlabelled) 那么一个问题可以用缩写代替,如ULA表示 \(n\) 个无标号的球分给 \(m\) 个有标号的盒子,一共有多少种方案。 现在你的任务是,给定问题的缩写和 \(n,m\) ,求方案数对 \(998244353\) 取模后的值。 LLA 这个很明显答案是 \(m^n\) ,每一个球有 \(m\) 种选择 LLB 发现这个条件不好满足,考虑容斥,每次强制枚举 \(i\) 个盒子里面没有球 \[ ans = \sum_{i = 0}^m\binom{n}{i}(m - i)^n \] LLC 我们发现,因为要求球全部放入盒子,所以当 \(n > m\) 肯定无解 否则答案就是 \[ \binom{m}{n}\times n! \] 看看那几个盒子里面有球,并且因为球是不同的,所以要再乘上排列数 LUB 发现LUB和LLB的区别就是其实就是 \(\{1,2,3\},\{4,5\}\) 和 \(\{4,5\}\

组合数学(部分)

雨燕双飞 提交于 2019-12-01 16:48:44
(转) 错排: 设 \((a_1,a_2,...,a_n)\) 是 \(\{1,2,...,n\}\) 的全排列,若对任意的 \(i\in\{1,2,..,n\}\) 都有 \(a_i\ne i\) ,则称 \((a_i,a_2,...,a_n)\) 是 \(\{1,2,...,n\}\) 的错位排列。 用 \(D_n\) 表示 \(\{1,2,...,n\}\) 的错位排列的个数,有: \(D_n=n!*(1-\frac1 1!+\frac1 2!-\frac1 3!+...+\frac{(-1)^n}n!)\) 圆排列: 从 n 个不同元素中选取 r 个元素,不分首尾地围成一个圆圈的排列叫做圆排列,其排列方案数为: \(\frac{A(n,r)}{r}\) 当 r=n 时,则为圆排列的全排列,其排列方案数为: \(\frac{n!}{n}=(n-1)!\) 第二类斯特林数: \(S(n,m)\) 表示有 \(n\) 个有区别小球,要放进 \(m\) 个相同盒子里,且每个盒子非空的方案数 考虑一个很容易的递推: \[S(n,m)=S(n−1,m−1)+m∗S(n−1,m)\] 考虑组合意义: 假设前面的 \(n−1\) 个球丢进了 \(m−1\) 个组,因为每个组非空,所以这个球只有一种选择,自己一组 如果前面的球已经分成了 \(m\) 组,那么,这个球就有 \(m\) 种放法

组合数学学习小记

家住魔仙堡 提交于 2019-11-30 23:07:10
有关组合数学的小记, 不喜勿喷 1.第一类斯特林数:表示将$ n$ 个不同元素构成 \(m\) 个圆排列的数目。 递推式: \(s(n,m)=s(n-1,m-1)+s(n-1,m)*(n-1)\) 。 递推式证明如下: 我们考虑第 \(n\) 个元素放的位置。 (1)前 \(n-1\) 个元素构成了 \(m-1\) 个圆排列,第 \(n\) 个元素独自构成一个圆排列: \(s(n-1,m-1)\) (2)前 \(n-1\) 个元素构成了 \(m\) 个圆排列,第 \(n\) 个元素插入到任意元素的左边: \((n-1)*S(n-1,m)\) 综上: \(s(n,m)=s(n-1,m-1)+s(n-1,m)*(n-1)\) 。 对于第一类斯特林数我们有以下特点: 1. \(s(n,n-2)=2*C(n,3)+3*C(n,4)\) 2. \(s(n,n-1)=C(n,2)\) 3. \(\sum_{i=0}^{n}s(n,i)=n!\) 2.第二类斯特林数:表示将 \(n\) 个不同的元素拆分成 \(m\) 个非空集合的方案数。 递推式: \(S(n,m)=S(n-1,m-1)+m*S(n-1,m)\) 。 同理,我们还是考虑第 \(n\) 个元素的放置情况。 (1)前 \(n-1\) 个元素构成了 \(m-1\) 个集合,那么第 \(n\) 个元素单独构成一个集合: \(S(n-1

神奇的组合数学——卡特兰数

别来无恙 提交于 2019-11-30 19:42:17
卡特兰数: 定义: 令 h ( 0 ) = 1 , h ( 1 ) = 1 //--> ,Catalan数满足递推式。 h ( n ) = h ( 0 ) × h ( n − 1 ) + h ( 1 ) × h ( n − 2 ) + . . . + h ( n − 1 ) × h ( 0 ) ( n ≥ 2 ) //--> 。 通项公式 : 证明如下 (摘自TAOCP的原练习题)(数竞党很少用不严格证明的定理): 解决问题: 1.括号对:合法的括号对对数答案为 h ( n ) //--> 。 2.二叉树:合法的树有答案为 h ( n ) //--> 。 3.分多边形:有 h ( n ) //--> 种分法,用这个可以简单的证明卡特兰数的通项: 不妨设 h ( i ) //--> 为 i //--> 边形的答案,明显,有 h ( i ) = h ( n ) = h ( 1 ) × h ( n − 1 ) + h ( 2 ) × h ( n − 2 ) + . . . + h ( n ) h ( 0 ) 。 //--> 又因为我们可以得到,总共的分法有 C ( n , n 2 ) //--> 个,不合法的是一个“逆序相交”,从而不合法的有: ∑ C ( n − t , t ) ∗ C ( t , 1 ) //--> 故相减可得有 所以得证(肯定有人注意到了,这个 h ( n ) //

[TJOI2015]组合数学

筅森魡賤 提交于 2019-11-30 13:10:24
题目 学习了 \(\rm Dilworth\) 定理,即 偏序集的最小全序集划分等于最大反链长度 定理的内容看起来非常自闭,偏序集、全序集和反链都是个啥 偏序集其实非常常见,经典的二维偏序、三维偏序其实就是最基本的偏序关系,比如说一个二元组集合 \(A\) ,对于 \((x_1,y_1),(x_2,y_2)\in A\) ,当 \(x_1\leq x_2,y_1\leq y_2\) 时我们称 \((x_1,y_1)\leq (x_2,y_2)\) ,则 \((A,\leq )\) 为一个偏序集 如果存在 \(x_1\leq x_2,y_1>y_2\) ,我们就无法在 \((A,\leq)\) 这个偏序集中定义 \((x_1,y_1),(x_2,y_2)\) 的大小关系,那么就称 \((x_1,y_1),(x_2,y_2)\) 在 \((A,\leq)\) 中不可比 全序集是偏序集的一个子集,如果 \(B\subseteq A\) ,且 \(\forall (x_1,y_1),(x_2,y_2)\in B\) ,存在 \((x_1,y_1)\leq (x_2,y_2)\) 或 \((x_2,y_2)\leq (x_1,y_1)\) ,即两两元素可比,则称 \(B\) 为 \(A\) 的一个全序集 如果对于 \(A\) 的一个子集,其中元素两两不可比,则称该子集为一个反链

组合数学

核能气质少年 提交于 2019-11-30 12:32:01
一,前置知识——两个计数原理 1,加法原理:完成某一个事情有n种做法,则有n种方案。 2,乘法原理:完成某一个事情有n个步骤,完成第一个步骤有a 1 种方法,完成第二个步骤有a 2 种方法, ......完成第n个步骤有a n 种方法,那么完成这件事情一共有(a 1 *a 2 *a 3 *......*a n )种方案。 二,排列数 线性排列: 首先看一个简单的问题,有n个人站队,一共有n个位置,考虑顺序,一共有多少种方案数。 运用加法原理可知,在站第一个位置的时候一共有n种方案,因为第一个位置已经站了一个人了,所以 在站第二个人的时候有n-1种方案,以此类推。 再由乘法原理可知,总方案数=n*(n-1)*....*(n-n+1)=n! 这个东西记作P n n 称为全排列数。 然后扩展向一般,有n个人站队,一共只有m个位置,考虑顺序,一共有多少种方案数。 不难想到,总方案数=n*(n-1)*......*(n-m+1); 这个就是线性排列数的通式记作 P n m ; P n m =n!/(n-m)!; 然后再介绍一些奇奇怪怪的排列 1,相异元素可重复排列 排列总数=n m 2,圆排列 从n个元素种选取出m个元素,不分首尾地排成一个圆圈的排列叫做圆排列,其排列方案数为 P n m /m; 理解:因为不分首尾了之后,会出现m个相同的圆。 3,不全相异元素的排列 如果在n个元素中有n 1

青原樱(组合数学)

帅比萌擦擦* 提交于 2019-11-29 06:04:45
n个位置m盆花,两盆花之间必须有一个空位,问有多少种合法情况。 先考虑把m盆花都放进一个位置里,那么剩下的位置有n-m个,m盆花要插到剩下的位置的空隙当中去,方案数为: c[n-m+1][m] 又因为每盆花各不相同,最后答案还得乘个m的全排列 化个简发现答案是: (n-m+1)!/(n-2m+1)! 于是直接一个for循环搞定,如果答案为0的花在for循环中ans一定会被更新为0 代码: #include <bits/stdc++.h> #define int long long #define sc(a) scanf("%lld",&a) #define scc(a,b) scanf("%lld %lld",&a,&b) #define sccc(a,b,c) scanf("%lld %lld %lld",&a,&b,&c) #define schar(a) scanf("%c",&a) #define pr(a) printf("%lld",a) #define fo(i,a,b) for(int i=a;i<b;++i) #define re(i,a,b) for(int i=a;i<=b;++i) #define rfo(i,a,b) for(int i=a;i>b;--i) #define rre(i,a,b) for(int i=a;i>=b;--i) #define

Codeforces 722E 组合数学 DP

ぃ、小莉子 提交于 2019-11-28 22:16:16
题意:有一个n * m的棋盘,你初始在点(1, 1),你需要去点(n, m)。你初始有s分,在这个棋盘上有k个点,经过一次这个点分数就会变为s / 2(向上取整),问从起点到终点的分数的数学期望是多少? 思路:按照套路,先把这k个点按照pair的方式进行排序,设dp[i][j]为从起点到点i之前经过了至少j个减分点,到点i的数学期望。那么所有在它之前的可以向它转移的点向它转移。那么dp[i][j] = Σ(dp[u][j - 1] - dp[u][j]) * g(u, i)。其中g(u, i)是u, i之间没有限制条件的走法数目,用组合数学的方法计算即可。这样相当于是前面恰好走过j个点 + 可能走过大于一个点的方式转移过来,这样可以保证计数的不重不漏。 代码: #include <bits/stdc++.h> #define INF 0x3f3f3f3f #define db double #define LL long long #define pii pair<int, int> using namespace std; const int maxn = 200010; const LL mod = 1e9 + 7; LL dp[2010][40]; pii a[2010]; LL v[maxn], inv[maxn]; LL qpow(LL x, LL y) { LL ans

洛谷P5520 青原樱(组合数学)

戏子无情 提交于 2019-11-28 15:28:56
首先,种树不外乎三种情况:两头有树、一头有数、两头都没树。这三种情况互不影响,这里只讨论两头有树的情况。 不考虑树的顺序,则根据插板法把问题化归为如下情况:把$n-m$个空位安排到$m-1$个间隔里,要求每个间隔非空。即把$n-m$个元素划分成$m-1$个非空段的方案数。再用一次插板法可知答案为$C^{m-2}_{n-m-1}$。 同理可得另外两种情况的答案。合并得到最终答案:$(C^{m-2}_{n-m-1}+2C^{m-1}_{n-m-1}+C^m_{n-m-1})\times m!$(一头有树有左右两种可能) 由于没想到可以约分就直接用质因数分解硬做了 #include<cstdio> #include<cstring> typedef long long ll; int p[50],pcnt=0,mod; void exgcd(int a,int b ,int &x,int &y){ if(!b){x=1;y=0;} else{ exgcd(b,a%b,y,x); y-=a/b*x; } } inline int inv(int a){ int x,y; exgcd(a,mod,x,y); return x<0?x+mod:x; } inline int fp(int a,int p){ int s=1; while(p){ if(p&1)s=(ll)s*a%mod; a=