2016 UESTC Training for Dynamic Programming D - 柱爷的恋爱 区间dp、记忆化搜索

D - 柱爷的恋爱

Time Limit: 1000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
Submit  Status

她手里有刚刚收到从远方的括号序列(仅包含( ) [ ]的序列),然而序列已经是一团乱麻,不堪入目,柱爷看到她坐在位子掩面哭泣,便上前安慰一番,

她向柱爷提出自己的"无理"申请.

她"蛮横"地要求柱爷计算出:删去这个括号序列的一个子集(不可以把整个括号序列都删去,那可是她的心爱之物;可以不完全删;子集可能是不连续的;

子集可能为∅),使得这个括号序列合法的方案数.

这个方案数可能很大,所以她只要求柱爷计算出这个方案数%1000000007就好了(她心疼柱爷,不想让柱爷打高精度).

你能帮柱爷解决这个恋爱中的小小问题吗?

Input

第一行一个整数N,表示括号序列的长度

接下来一行包含一个长度为N的括号序列字符串

数据保证:

  • 1 <=  N  <= 300

Output

一个正整数,表示柱爷要回答她的数.

Sample input and output

Sample Input Sample Output
4
()[]
3
3
())
2

Hint

合法的括号序列定义如下:

  • 如果S是合法序列,那(S)和[S]也是合法序列;
  • 如果A和B都是合法序列,那么AB也是合法序列.
  • 例如,下面的字符串都是合法序列:
  • (), [], (()), ([]), ()[], ()[()]

Source

2016 UESTC Training for Dynamic Programming


My Solution

记忆化搜索

dp[a, b] 表示 [a, b) 内的方案数;

如果line[a] 要去掉, 则直接转移 dp[a, b] = dfs(a+1, b);

如果line[a]不去掉的, 那么如果line[a] 是'('就去找line[i] == ')',如果'['就找line[i] == ']', 找到一个算一个, 同时 [a+1, i) 和 [i+1, b)也要合法序列

然后dfs(a + 1, i) * dfs(i+1, b);

然后调用dfs(0,n) 就好了,找出[0,n) 内的方案数:

复杂度O(n^3);

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 300 + 8, HASH = 1000000007;
LL dp[maxn][maxn]; //主要是 有 (int)a*(int)b 的这个可能int溢出
string line;
/*
inline LL add(int a, int b)
{
    LL c = a + b;
    return c >= HASH ? c - HASH : c;
}
*/
LL dfs(int a, int b)
{
    LL& res = dp[a][b];
    if(res == -1){
        if(a == b){
            res = 1;
        }
        else{
            res = 0;
            //line[a] is not removed
            char goalbra = '\0';
            if(line[a] == '('){
                goalbra = ')';
            }
            else if(line[a] == '['){
                goalbra = ']';
            }
            if(goalbra != '\0'){
                for(int i = a + 1; i < b; i++){
                    if(line[i] == goalbra){
                        res = (res + dfs(a + 1, i)*dfs(i + 1, b)) % HASH;
                    }
                }
            }
            //line[a] is removed
            res = (res + dfs(a + 1, b)) % HASH;
        }
    }
    return res;
}

int main()
{
    #ifdef LOCAL
    freopen("a.txt", "r", stdin);
    #endif // LOCAL
    int n;

    scanf("%d", &n);
    cin>>line;
    memset(dp, 255, sizeof dp);
    //cout<<dp[0][0]<<endl;
    printf("%lld", dfs(0, n) - 1);//不能全部去掉,所有有个 [a,a) 不能return 1 故这里 subtract 1 to find the wanted answer

    return 0;
}

Thank you!

                                                                                                                                               ------from ProLights




你可能感兴趣的:(dp,ACM,for,Training,记忆化搜索,区间DP)