• [学习笔记][组合数学]卡特兰数的一个组合意义


    引入

    • 卡特兰数 (Cat_n) 的定义为 (n)(1)(n)(-1) 构成的,任意前缀和不小于 (0) 的序列个数

    • 众所周知卡特兰数有通项公式:

    • [Cat_n=frac{inom{2n}n}{n+1} ]

    • 可以通过容斥来推导(在任意 (n)(1)(n)(-1) 构成的序列中,找到第一个小于 (0) 的前缀和设其位置为 (i) ,将序列 ([1,i]) 内的数全部取反)

    • 不过这里讲一种比较巧妙的组合意义

    前置定理

    • 对于一个 (n)(1)(n)(-1) 构成的序列 (s) ,存在一个 (0le i<2n) 使得 (s_{i+1dots 2n}+s_{1dots i}) (即 (i) 次循环位移之后)的任意前缀和不小于 (0)

    • 证明:将 (i) 定为 (s) 最小前缀和的位置,分 ([i+1,2n])([1,i]) 两类讨论可以得出任意前缀和不小于 (0)

    组合意义

    • 下面为了方便,假设所有 (n)(1) 都是不一样的,所有 (n)(-1) 也都是不一样的(即 (n)(1)(n)(-1) 组成的数组,所有 (n!) 种重排的方案中有多少种满足任意前缀和不为负),最后除以 ((n!)^2) 即可,设所有的 (1) 标号从 (1)(n) ,所有的 (-1) 标号从 (n+1)(2n)

    • 考虑在末尾再加一个标号为 (2n+1)(-1) ,组成一个环

    • 考虑如何从环上删掉一个 (-1) ,构成一个合法的卡特兰序列

    • 相当于以任意位置破环为链形成一个长度为 (2n+1) 的序列之后,选取一个 (1le ile 2n+1) 使得 (s_{i+1dots 2n+1}+s_{1dots i}) 的任意前缀和(最后一个位置除外)不为负

    • 类似于前置定理中提到的内容,我们可以找到一个 (i) 使得 (s)(i) 个数的和最小(有多个则取 (i) 最小者),易得取这个 (i)唯一合法的

    • 故一个环存在唯一的删掉一个 (-1) 的方法使其变成合法的序列

    • 而我们需要保证删掉 (-1) 之后剩下的数标号必须从 (1)(2n) ,也就是这个唯一的 (-1) 标号必须为 (2n+1)

    • 故所有的 (2n+1) 个元素的环中,平均 (n+1) 个环中就有一个合法的环

    • 于是我们得出:

    • [Cat_n=frac{(2n)!}{(n+1)(n!)^2}=frac{inom{2n}n}{n+1} ]

    拓展

    • 卡特兰数的容斥推导和上面介绍的推导各有不同的拓展空间,下面的题目是这个组合意义的一个拓展

    清华集训2016 你的生命已如风中残烛

    题意

    • (m=sum_{i=1}^nw_i) 个数,前 (n) 个中第 (i) 个为 (w_i-1) ,剩下的 (m-n) 个数都是 (-1)

    • 求对这 (m) 个数 (m!) 种重排的方案中,有多少种满足重排后的序列任意前缀和不为负

    • (nle 40,1le w_ile 10^5)

    做法

    • 和上面卡特兰数的组合意义推导一样,在序列的最后放上一个标号为 (m+1)(-1) ,组成一个环

    • 易得对于一个环,删掉一个 (-1) 构成合法序列的方案是唯一的

    • 于是我们的要求就变成了限制这个唯一的 (-1) 的标号必须为 (m+1)

    • 而这个环上 (-1) 的个数为 (m-n+1)

    • 故答案为 (frac{m!}{m-n+1})

    代码

    #include <bits/stdc++.h>
    
    template <class T>
    inline void read(T &res)
    {
    	res = 0; bool bo = 0; char c;
    	while (((c = getchar()) < '0' || c > '9') && c != '-');
    	if (c == '-') bo = 1; else res = c - 48;
    	while ((c = getchar()) >= '0' && c <= '9')
    		res = (res << 3) + (res << 1) + (c - 48);
    	if (bo) res = ~res + 1;
    }
    
    const int rqy = 998244353;
    
    int n, m, ans = 1;
    
    int main()
    {
    	int x;
    	read(n);
    	for (int i = 1; i <= n; i++) read(x), m += x;
    	for (int i = 1; i <= m; i++)
    		if (i != m - n + 1) ans = 1ll * ans * i % rqy;
    	return std::cout << ans << std::endl, 0;
    }
    
  • 相关阅读:
    企业级工作流解决方案(七)--微服务Tcp消息传输模型之消息编解码
    企业级工作流解决方案(一)--总体介绍
    将博客搬至CSDN
    利用LiveGBS通过GB28181实现PC、手机WEB页面对监控摄像头直播以及语音对讲
    如何利用LiveQing流媒体服务搭建视频快照直播监控-配置定时快照、实时检索
    LiveGBS-GB28181国标流媒体接入安防摄像头或平台时目录结构设备树状展示图
    LiveNVR实现安防摄像头RTSP WEB无插件直播中ONVIF预制位接口的使用说明
    LiveGBS GB28181国标流媒体对几万路摄像头接入时如何配置切换成Mysql_Mariadb数据库
    安防摄像通过GB28181协议实现云端录像存储与回放
    GB28181实现摄像头语音对讲
  • 原文地址:https://www.cnblogs.com/xyz32768/p/11961382.html
Copyright © 2020-2023  润新知