标签:using return class 卡特兰数 依次 n+2 name turn mem
一套有趣的题目
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
首先我们定义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;
}
标签:using return class 卡特兰数 依次 n+2 name turn mem
原文地址:https://www.cnblogs.com/zhuier-xquan/p/11519665.html