UESCTC-2016dp专题 D 柱爷的恋爱

                                           柱爷的恋爱

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

题目链接

http://acm.uestc.edu.cn/#/contest/show/96

Description

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

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

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

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

Input

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

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

数据保证:

  • 1N3001≤N≤300

Output

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

Sample input and output

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

Hint

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

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

题意

 给你一个字符序列,对他进行删除操作,可以不删,但不能全删,问最后得到合法序列的删除方法数

思路

区间dp,定义dp[l][r]为处理完[l,r]区间后得到的合法序列的个数,考虑转移方程,可由两个状态转移而来:

1.删除第l个括号,则此时dp[l][r]=dp[l+1][r]

2.不删除第l个括号,则需要在后面枚举与其配对的括号,将两个区间分别操作,将结果相乘即可。

注意不要爆int了。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn=300+7;
const int mod=1000000007;
int n;
string s;
long long int dp[maxn][maxn];

bool match(int l,int r)  //匹配括号
{
    if((s[l]=='('&&s[r]==')')||(s[l]=='['&&s[r]==']'))
        return true;
    return false;
}
long long int dfs(int l,int r)
{
    if(~dp[l][r]) return dp[l][r];
    long long int &ans=dp[l][r]=0;
    if(l>r) return ans=1;
    if(l==r) return ans=1;
    ans=dfs(l+1,r);   //删除括号
    ans%=mod;
    for(int i=l;i<=r;i++){   //枚举配对
        if(match(l,i)){
            ans+=dfs(l+1,i-1)*dfs(i+1,r);
            ans%=mod;
        }
    }
    return ans%mod;
}
int main()
{
     scanf("%d",&n);
     cin>>s;
     memset(dp,-1,sizeof(dp));
     long long int ans=(dfs(0,n-1)-1)%mod;
     printf("%lld",ans);
     return 0;
}
原文地址:https://www.cnblogs.com/wangdongkai/p/5491661.html