时间:2016-04-07 15:23:14 星期四
题目编号:[2016-04-07][codeforces][629][C][Famil Door and Brackets]
题目大意:
- 给定一个长度为m只含有’(‘和’)’的字符串,问串p,串q的方案数,使得p+s+q为一个合法的括号序列
- 合法的括号序列
- ’(‘和’)’的数目一样
- 该串的任意前缀满足 ‘(‘的数目大于等于’)’的数目
分析:
- p+s+q要满足题意,那么首先得保证p+s这一串的任意子串满足条件2,所以p中’(‘的数目大于’)’数目,至少为s中对应的差值
- 枚举p和q的方案数目,可以通过dp来计算
- dp[i][j] 表示长度为i的串,’(’ 比’)’多j个的方案数目
- dp[i][j] = dp[i-1][j-1] + dp[i-1][j+1]
- dp[i][0] = dp[i - 1][1];
遇到的问题:
- dp 和 ans运算后都要 %
- 注意无解的情况,并不是所有长度的p都能有解的
- 后面的k要进行范围的判断,可能出现无解,就是i无论去多少,cur+j的k都小于0,
- 或者cur是正的,j是正的,加起来超过n-m,
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxdn = 2000 + 10;
const int MOD = 1E9 + 7;
LL dp[maxdn][maxdn];
void dpini(int d){
dp[0][0] = 1;
for(int i = 1; i <= d;++i){
dp[i][0]=dp[i-1][1];
for(int j = 1 ; j <=i ;++j){//最多多j个,不能再多
dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j + 1])%MOD;
}
}
}
char str[100000 + 10];
int main(){
int n,m;
scanf("%d%d%s",&n,&m,str);
dpini(n - m);
int pre = -0x3f3f3f3f,cur = 0;//确定s中')'比'('最多会多 多少记为pre,那么串p中的'('比')'至少多pre个
for(int i = 0;i <m ; ++i){
if(str[i] == ')') ++cur;
else --cur;
pre = max(pre,cur);
}
cur = -cur;//cur上面处理结束之和,表示为s中'('比')'多的数目,
LL ans = 0;
for(int i = 0;i <= n - m;++i){
for(int j = max(pre,0);j <= i;++j){
int k = j + cur;
if(k >= 0 && k <= n - m){//这里要限制范围
ans += (dp[i][j] * dp[n - m - i][k]) % MOD;
ans %= MOD;
}
}
}
printf("%I64d\n",ans);
return 0;
}