时间: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;}