Hihocoder 1492 : Parentheses Sequence
2017-04-01 16:22:16
笔试好题,学习一下。。
题意:给出长度 <= 1000 的括号串,问最少再插入多少个括号使其 perfect match,以及此时得到的最终串的种类数。
对于括号问题,经典的转化:左括号+1,右括号-1,则 perfect match时任意前缀和 >=0。
IDEA:明显的dp,需要维护的量:下标 i,前缀值 j,最少插入数 k,种类数 p
不能直接dp[i][j][k],三维DP,因此考虑把 k 和 p 合在一起考虑,可以用 dp[i][j] = pair (k,p)
即:dp[i][j] : 考虑原串前 i 个括号,插入括号后前缀和为 j,dp存下最少插入数和当前种类数(开pair或者开两个数组)
考虑到:如果在 ')' 前后插入 ')',会导致重复,因此我们只在 ')' 前插入 '(','('前只插')'。
之后就好做了,每层dp有一个类似前缀积累和的计算,注意细节、不要算重就好。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> using namespace std; const int MAXN = 1010; const int mod = 1e9 + 7; char s[MAXN]; int dp[MAXN][MAXN],DP[MAXN][MAXN]; void Update(int a1,int b1,int a2,int b2,int d){ if(dp[a1][b1] == dp[a2][b2] + d){ DP[a1][b1] = (DP[a1][b1] + DP[a2][b2]) % mod; } else if(dp[a1][b1] > dp[a2][b2] + d){ dp[a1][b1] = dp[a2][b2] + d; DP[a1][b1] = DP[a2][b2]; } } int main(){ scanf("%s",s + 1); int len = strlen(s + 1); s[len + 1] = '('; memset(dp,0x3f,sizeof(dp)); dp[0][0] = 0,DP[0][0] = 1; for(int i = 1; i <= len + 1; ++i){ if(s[i] == '('){ Update(i,len,i - 1,len,1); for(int j = len - 1; j >= 1; --j) Update(i,j,i - 1,j,1),Update(i,j,i,j + 1,1); for(int j = len; j >= 1; --j) Update(i,j,i - 1,j - 1,0); } else{ Update(i,0,i - 1,0,1); for(int j = 1; j <= len; ++j) Update(i,j,i - 1,j,1),Update(i,j,i,j - 1,1); for(int j = 0; j <= len; ++j) Update(i,j,i - 1,j + 1,0); } } printf("%d %d\n",dp[len + 1][1],DP[len + 1][1]); return 0; }