卡特兰数

一套有趣的题目

  1. 1,2,3…n 以此进栈,求有多少种可能的出栈序列。
  2. 由n对括号形成的合法的括号序列有多少个。
    1. N<=10^5
    2. 这个问题还有很多其他的表达形式。
  3. n个节点共能构成多少种二叉树,左右子树是认为不同。
  4. 凸多边形的三角划分的方案数:把一个凸多边形用n-3条直线连接n-3对顶点,共形成n-2个三角形,求方案数。(n+2边形三角划分)
  5. 一个n*n的格子,从(0,0)走到(n,n),求不跨过(0,0)->(n,n)这条直线的路径方案数

eg2:设f[i]表示i对括号的方案数,那么有:\(f[n]=\sum\limits_{i=0}^{n-1}f[i]*f[n-i-1]\)

卡特兰数:

我们设f[n]表示n个数依次进栈所能形成的出栈序列数。

似乎和之前不一样,好像不是划分成一段一段那样的简单形式。

我们可以考虑另一种形式的状态转移方式,以转移到子问题。

注意一段一段划分我们可以枚举最后一段的起点,但是这里不是一段一段的,我们要考虑另外的转移方式。

实际上我们发现我们可以枚举1这个数是什么时候出栈的。

那么我们可以得到:\(f[n]=\sum\limits_{i=0}^{n-1}f[i]*f[n-i-1]\)

一个经典题

有n个数,选择其中若干数,使得每连续k个数中都至少有一个数被选中,且选出的数的和最小。

k<=n<=1000

k<=n<=100000

SOLUTION:

首先我们定义f[i]表示按照满足题目要求的选择选取,并且第i个数一定被选中的最小和是多少;

f[1]=a[1];

\(f[i]=min\{f[j]+a[i]|i-j<=k\}\)

然后可以\(O(n^2)\)的做;

考虑优化:

\(f[i]=min\{f[j]|i-j<=k\}+a[i]\)

显然可以考虑单调队列优化w

用优先队列优化就好了√;

#include<bits/stdc++.h>

using namespace std;

int n,k;
int a[1010],dp[1010];

int main(){
	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	memset(dp,0x3f,sizeof(dp));
	dp[0]=0;
	dp[1]=a[1];
	for(int i=2;i<=n;i++) {
		for(int j=i-1;i-j<=k&&j>=0;j--)
			dp[i]=min(dp[i],dp[j]+a[i]);
		//cout<<dp[i]<<endl;
	}
	printf("%d",dp[n]);
	return 0;
}
posted @ 2020-05-09 19:55  Sweetness  阅读(167)  评论(0编辑  收藏  举报