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;
}

 

posted @ 2017-04-01 16:34  Naturain  阅读(471)  评论(1编辑  收藏  举报