柱爷的恋爱
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的括号序列字符串
数据保证:
- 1≤N≤3001≤N≤300
Output
一个正整数,表示柱爷要回答她的数.
Sample input and output
Sample Input | Sample 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; }