[2016-04-07][codeforces][629][C][Famil Door and Brackets]

  • 时间: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,
  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. typedef long long LL;
  5. const int maxdn = 2000 + 10;
  6. const int MOD = 1E9 + 7;
  7. LL dp[maxdn][maxdn];
  8. void dpini(int d){
  9. dp[0][0] = 1;
  10. for(int i = 1; i <= d;++i){
  11. dp[i][0]=dp[i-1][1];
  12. for(int j = 1 ; j <=i ;++j){//最多多j个,不能再多
  13. dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j + 1])%MOD;
  14. }
  15. }
  16. }
  17. char str[100000 + 10];
  18. int main(){
  19. int n,m;
  20. scanf("%d%d%s",&n,&m,str);
  21. dpini(n - m);
  22. int pre = -0x3f3f3f3f,cur = 0;//确定s中')'比'('最多会多 多少记为pre,那么串p中的'('比')'至少多pre个
  23. for(int i = 0;i <m ; ++i){
  24. if(str[i] == ')') ++cur;
  25. else --cur;
  26. pre = max(pre,cur);
  27. }
  28. cur = -cur;//cur上面处理结束之和,表示为s中'('比')'多的数目,
  29. LL ans = 0;
  30. for(int i = 0;i <= n - m;++i){
  31. for(int j = max(pre,0);j <= i;++j){
  32. int k = j + cur;
  33. if(k >= 0 && k <= n - m){//这里要限制范围
  34. ans += (dp[i][j] * dp[n - m - i][k]) % MOD;
  35. ans %= MOD;
  36. }
  37. }
  38. }
  39. printf("%I64d\n",ans);
  40. return 0;
  41. }


来自为知笔记(Wiz)


posted on 2016-04-07 16:34  红洋  阅读(141)  评论(0)    收藏  举报

导航