和谐的奶牛Balanced Cow Breeds

题目

农夫约翰的奶牛们排成了一条直线,每只奶牛都有一个标识符,这个标识符是左括号或者右括号。约翰希望将这个奶牛序列分成两个子序列,并且不改变序列中原来的字符顺序。同时,要求这两个子序列都是平衡序列。
平衡序列是这么定义的:序列中左括号和右括号的个数是一样的,同时这个序列的所有前缀串中左括号的个数不少于右括号的个数。

例如图1都是平衡序列。
()
(())
()(()())
图2都不是平衡序列。
)(
())(
((())))
请你帮助约翰计算将原来的奶牛序列分成两个平衡子序列的方案数。

输入

只有一个奶牛的序列,都是由左括号和右括号组成的。

输出

总的方案数。

样例输入

(())

样例输出

6

数据范围限制

序列的长度是 1 1 1 1000 1000 1000

题解

We’ll call the two breeds A and B for convenience. Let the input string S = s 1 s 2 . . . s n S = s_1s_2...s_n S=s1s2...sn. We will give a dynamic programming algorithm working backwards from the end of the string.

Let f ( i , A o p e n , B o p e n ) f(i,A_{open}, B_{open}) f(i,Aopen,Bopen) be the number of ways to assign s i . . . s n s_i...s_n si...sn to breeds such that the resulting two parentheses-strings are balanced, given that we have A o p e n A_{open} Aopen unmatched left-parenthesis of type A and B_open unmatched left-parentheses of type B. If S [ i ] = = ′ ( ′ S[i]=='(' S[i]==(, then f ( i , A o p e n , B o p e n ) = f ( i + 1 , A o p e n + 1 , B o p e n ) + f ( i + 1 , A o p e n , B o p e n + 1 ) f(i,A_{open}, B_{open}) = f(i+1, A_{open}+1, B_{open}) + f(i+1, A_{open}, B_{open} + 1) f(i,Aopen,Bopen)=f(i+1,Aopen+1,Bopen)+f(i+1,Aopen,Bopen+1), since we can assign the parenthesis to breed A or breed B. If S [ i ] = = ′ ) ′ S[i]==')' S[i]==), then we can assign the parenthesis to breed A as long as A o p e n > 0 A_{open} > 0 Aopen>0, and to B as long as B o p e n > 0 B_{open} > 0 Bopen>0.

The base case is i=n, in which case we processed the whole string without violating any invariants. As the total number of ')'s equals to the total number of ′ ( ′ '(' (s, we wil end up with two balanced strings of parentheses. Therefore we can start with so f ( n , 0 , 0 ) = 1 f(n, 0, 0) = 1 f(n,0,0)=1.

We have 0 &lt; = i &lt; = n , 0 &lt; = A o p e n &lt; = n , 0 &lt; = B o p e n &lt; = n 0 &lt;= i &lt;= n, 0 &lt;= A_{open} &lt;= n, 0 &lt;= B_{open} &lt;= n 0<=i<=n,0<=Aopen<=n,0<=Bopen<=n, so the number of states is O ( n 3 ) O(n^3) O(n3), and there is O ( 1 ) O(1) O(1) non-recursive overhead for each state, so this leads to an O ( n 3 ) O(n^3) O(n3)solution.

Unfortunately, O ( n 3 ) O(n^3) O(n3) isn’t fast enough with n = 1 , 000 n=1,000 n=1,000. We can do better by noticing that B o p e n B_{open} Bopen is uniquely determined by i and A o p e n ( b e c a u s e A o p e n + B o p e n A_{open} (because A_{open} + B_{open} Aopen(becauseAopen+Bopen sums to the number of unmatched left-parentheses in s 1 . . . s i − 1 ) s_1...s_{i-1}) s1...si1). So it suffices to keep track of ( i , A o p e n ) (i, A_{open}) (i,Aopen), which gives O ( n 2 ) s t a t e s   a n d   a n O ( n 2 ) O(n^2) states \ and\ an O(n^2) O(n2)states and anO(n2) solution. This is fast enough.

Code

#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;
#define MOD 2012
#define MAXN 1010
int a[MAXN];
int main() 
{
    freopen("bbreeds.in","r",stdin);
    freopen("bbreeds.out","w",stdout);
    int l = a[1] = 1;
    for(int ch = cin.get();l > 0 && ch == '(' || ch == ')';ch = cin.get()) 
    {
        int dir = ch == '(' ? 1 : -1;
        l += dir;
        for(int j = dir < 0 ? 1 : l;1 <= j && j <= l; j -= dir) 
        {
            a[j] += a[j - dir];
            if(a[j] >= MOD) 
                a[j] -= MOD;
        }
    a[l + 1] = 0;
  }
  cout << (l == 1 ? a[1] : 0) << endl;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值