区间DP
2955 -- Brackets
给定一个由字符 a1a2 ... an 组成的括号序列,你的目标是找到最长的正则括号序列的长度,它是 s 的子序列。也就是说,您希望找到最大的 m,使得对于索引 i1、i2、...、im,其中 1 ≤ i1 < i2 < ... < im ≤ n,ai1ai2 ... aim 是常规括号序列。
接下来就是强行把自己讲懂的……QAQ
子状态:我们想,既然最后要求的是从0到len-1的区间中有多少个括号被匹配,那这个答案是怎么推过来的呢?肯定是从它的前面推过来的,也就是0到len-2等等,那就设子状态为f[i][j],其中i表示起始位置,j表示终止位置。
转移方程:每一个区间都是它由括号划分成的 两段子区间之和 中的最大值, 即 f[i][j]=max(f[i][j],f[i+1][k-1]+f[k+1][j]+2),如果没有匹配的括号,说明可以略过第一个括号, 即f[i][j]=f[i+1][j]。
边界条件:若i>=j,则f[i][j]=0。当f[i][j]有值就直接返回,所以初始值应当设为-1。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
//scanf("",&);
const int inf = 0x3f3f3f, maxn=105;
string s;
int f[maxn][maxn];
int calc(int i,int j){
if(f[i][j]!=-1)
return f[i][j];
if(i>=j)
return f[i][j]=0;
f[i][j]=calc(i+1,j);
for(int k=i+1;k<=j;++k)//
if((s[i]=='('&&s[k]==')')||(s[i]=='['&&s[k]==']'))
f[i][j]=max(f[i][j],calc(i+1,k-1)+calc(k+1,j)+2);
return f[i][j];
}
int main(){
while(cin>>s){
if(s=="end") break;
memset(f,-1,sizeof(f));
int len=s.length();
calc(0,len-1);
cout<<f[0][len-1]<<endl;
}
return 0;
}
最长回文子序列长度
给你一个长度为n的序列,求最长回文子序列长度(子序列可不连续)。
法一:线性dp。可以求原串和其倒序串的最长公共子序列。
法二:区间dp。f[i][j]表示ij之间的最长回文子序列,则若ai与aj相同,f[i][j]=f[i+1][j-1]+2,否则 f[i][j]=max(f[i+1][j], f[i][j-1]),即分别求去掉头尾的最长回文子序列。
拓展:最长回文子串长度(子串必须连续)
既然一个串的子串只要有一个不满足回文就无法再扩展回文长度,那么我们可以直接设置bool数组,f[i][j]表示从i到j是否为回文串,则f[i][j]=f[i+1][j-1]&&(a[i]==a[j])。答案用ans=max(ans,j-i+1)维护即可。更优的办法:manacher。
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
石子合并
将n堆石子绕圆形操场排放,