首页 > 其他分享 >卡特兰数学习笔记

卡特兰数学习笔记

时间:2023-03-07 20:56:33浏览次数:53  
标签:直线 int 笔记 学习 leq ans 卡特兰 mod

参考了这篇博客

引入

\(n\) 个元素进栈序列为:\(1,2,3,4...n\),求总共有多少种出栈序列。

将进栈表示为 \(+1\),出栈表示为 \(-1\),则 \(1,3,2\) 的出栈序列可以表示为:\(+1,-1,+1,+1,-1,-1\)。

根据栈本身的特点,每个出栈序列的所有前缀和必然 \(\geq 0\),并且最终 \(+1\) 的数量等于 \(-1\) 的数量。

对于这样的问题,总的方案数就被称之为卡特兰数。

表达式

对于卡特兰数,有通项公式: \(C_n=C_{2n}^{n}-C_{2n}^{n+1}=\frac{C_{2n}^{n}}{n+1}\)。

同时也满足以下递推式: \(C_n=C_{n-1} \frac{4n-2}{n+1}\)。

[应用]骗我呢

给定 \(n,m\),求有多少个 \(n \times m\) 的矩阵,满足:

对于任意的 \(i,j\),都满足矩阵中第 \(i\) 行第 \(j\) 列的元素 \(x_{i,j}\) 有:

1.\(x_{i,j}<x_{i,j+1} (j<m)\);

2.\(x_{i,j}<x_{i-1.j-1}\);

3.\(0 \leq x_{i,j} \leq m\)。

结果对 \(10^9+7\) 取模,\(1 \leq n,m \leq 10^6\)。

思路:

注意到矩阵的每一行中有 \(m\) 个元素,一共有 \(0 \sim m\) 共 \(m+1\) 种取值,那么每一行有且仅有一个数不会被取到。

设 \(f_{i,j}\) 表示考虑到第 \(i\) 行,当前这一行不选 \(j\) 这个数的总方案。

考虑当前这一行不选 \(j\),前一行不选 \(k\),那么当 \(k>j+1\) 的时候,就会满足 \(x_{i,j+1}=x_{i-1,j+2}=j+1\),不满足第二条性质,于是就有 \(k \leq j+1\),那么就有 \(f_{i,j}=\sum_{k=0}^{j+1} f_{i-1,k}\)。

优化一下,可以得到:\(f_{i,j}=\sum_{k=0}^{j} f_{i-1,k}+f_{i-1,j+1}=f_{i,j-1}+f_{i-1,j+1}\)。

那么最终的答案就是 \(\sum_{j=0}^{m} f_{n,i}=f{n+1,m}\)。

考虑将 \(f_{i,j}\) 的递推关系映射到直角坐标系上。(图片源于这篇博客

image

不难发现,此时的答案就转化为了从 \((1,0)\) 走到 \((n+1,m)\) 的总方案数。

将第 \(2\) 行到第 \(n+1\) 行的点横坐标 \(+1\),可以得到:

image

此时的答案仍然是从 \((1,0)\) 走到 \((n+m+1,m)\) 的总方案数。

将起点平移到坐标原点 \((0,0)\),在点的两侧分别画出一条直线:

image

此时的方案数就是从 \((0,0)\) 出发,只能向上或向右走,且不能触屏到 \(A:y=x+1\) 和 \(B:y=x-m-2\) 这两条直线,最终走到 \((n+m+1,m)\) 点的总方案数。

假如不考虑直线的限制,那么答案就是 \(\binom{n+2m+1}{m}\)。

定义一个仅由 \(A,B\) 构成的字符串,如 \(AABBA\),表示这条路径先穿过了两次 \(A\) 直线,再穿过两次 \(B\) 直线,最后又穿过一次 \(A\) 直线到达终点,不难发现,同一条直线连续经过多次在计算的时候没有影响,所以把相同的部分合并为一次。最终的答案要分别减去以 \(A\) 开头的路径和以 \(B\) 开头的路径。

考虑将直线 \(B\) 关于直线 \(A\) 对称,那么对称过去后的方案数就可以通过组合数直接进行计算,同时也需要注意容斥减去重复的方案数。总的时间复杂度为 \(O(n)\)。

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=3e6+10,mod=1e9+7;
int n,m,fac[M],infac[M],inv[M];
void init()
{
	fac[0]=infac[0]=fac[1]=infac[1]=inv[0]=inv[1]=1;
	for(int i=2;i<M;i++) fac[i]=1ll*fac[i-1]*i%mod;
	for(int i=2;i<M;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	for(int i=2;i<M;i++) infac[i]=1ll*infac[i-1]*inv[i]%mod;
}
int C(int n,int m){if(n<0||m<0||n<m) return 0;return 1ll*fac[n]*infac[m]%mod*infac[n-m]%mod;}
int calc(int x,int y,int dir)
{
	if(x<0||y<0) return 0;int delta=dir?-m-2:1;
	return (C(x+y,y)-calc(y+delta,x-delta,dir^1)+mod)%mod;
}
void add(int &a,int b){a+=b;if(a>=mod) a-=mod;}
int main()
{
	scanf("%d%d",&n,&m);init();int ans=C(2*n+m+1,n);
	ans=(ans-calc(n-1,n+m+2,0)+mod)%mod;
	ans=(ans-calc(n+m+2,n-1,1)+mod)%mod;
	printf("%d\n",ans);
}

标签:直线,int,笔记,学习,leq,ans,卡特兰,mod
From: https://www.cnblogs.com/ListenSnow/p/17189616.html

相关文章

  • Android学习
    UIAndroidUI组件层次结构View背景:android:background="@mipmap/bg"android:background="#FF0000"内边距:android:padding="16dp"android:padding="@d......
  • Java官方笔记1编写运行Java程序
    你可能已经迫不及待想安装Java,写个Java程序跑起来了。但是在这之前,有些概念需要提前了解,因为Java跟C、C++和Python都有点不一样。编译和执行我们在文本文件中编写英文代......
  • python入门学习-1.从hello到函数的基本使用
    参考廖雪峰python教程starthelloworld创建一个hello.py文件,文件名只能是数字、字母、下划线的组合,输入:print('helloworld')在命令行执行代码:ztc@ztc-ubuntu:~/cod......
  • 2023、03、07学习总结之——Python学习_2
    1——Python程序设计中的整数类型没有取值范围限制,但受限于当前计算机的内存大小。2——表达式1+2*3.14>0的结果类型是:bool3——Python语言正确的标识符是(C)A.2youB.......
  • spring的初步学习
    引入单独使用spring只需引入<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version></de......
  • 2023年3月7日学习总结
    今天开始学习javaweb的开学测试,仔细阅读了题目要求,了解了基本的项目需求,先完成了第一个登陆页面的制作,学会了之前不了解的文本输入框的一些知识,接下来学习实现不同用户登录......
  • java -D的一些学习和使用
    背景java开发的程序有很多进行配置的方式可以通过yaml文件或者是xml文件也可以通过环境变量的方式.1.容器的话可以使用-e或者是env进行注入2.K8S的话可以通过co......
  • 2002年,我在台资企业搞信息化,才正式学习编程软件,当时用的delphi5,操作简单,编译速度快,拖
    2002年,我在台资企业搞信息化,才正式学习编程软件,当时用的delphi5,操作简单,编译速度快,拖拉控件,上手很快,这样陆陆续续使用到现在,出了不少作品,至今还在用delphi搞PC端软件......
  • Android 简单学习开源换肤框架(ThemeSkinning)
    Android简单学习开源换肤框架(ThemeSkinning)GitHub地址ThemeSkinning找到初始化View的入口并替换自定义的入口通常我们都是通过setContentView(intID)把View加载到我......
  • C++笔记-指针
    1.const指针和指向const的指针指向const的指针是在类型前加星号可以指向非const类型指针可以改变指向dereference不能改变值const指针是在类型后面加星号指针不可......