前言
一眼区间dp,实际线性dp
题目大意
最长括号匹配
题目描述
对一个由(,),[,]括号组成的字符串,求出其中最长的括号匹配子串。
对100%的数据,字符串长度<=1000000.
思路
第一眼看上去是区间dp模版,咋做我都大概想好了。看了眼数据范围,告辞。 考虑线性dp。
先尝试设一下 为以第 位为结尾的最长匹配子串长度。
开始定义了。首先可以看出,由[,(结尾的肯定匹配不上(这是废话),考虑在当前位置为],)的时候做转移。之后巧的地方要来了。
的上一位的长度为 对吗,那么我想要添加的话就只要 的位置能和 匹配上不就可以加一位了吗。之后只需要再加上 ,也就是左端点之前连起来的模式即可。总结整理一下。
伪代码:
当 时 :
如果 或同理的[]时:
之后在过程中取max和终点即可。很简单了。
代码
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const ll MAXN=1e6+5;
ll dp[MAXN];
char a[MAXN];
int main(){
cin>>(a+1);
ll n= strlen((a+1)),ans=0,e=0;
for (int i = 2; i <=n; ++i) {
if(a[i]==')'||a[i]==']'){
if((a[i]==')'&&a[i-dp[i-1]-1]=='(')||(a[i]==']'&&a[i-dp[i-1]-1]=='[')){
dp[i]=dp[i-1]+dp[i-dp[i-1]-2]+2;
if(dp[i]>ans){
ans=dp[i];
e=i;
}
}
}
}
for (ll i = e-dp[e]+1; i <=e ; ++i) {
cout<<a[i];
}
return 0;
}
总结
在很多时候看着好像是区间dp,实际上是线性dp。我们在选择dp方式的时候可以根据数据范围来判断。 已经可以初步判断为线性dp了, 可能是状压dp, 大概是区间dp了。