链接:https://www.nowcoder.com/acm/contest/188/D
来源:牛客网

题目描述

小w很生气
小w有一个长为n的括号序列
愤怒小w想把这个括号序列分为两个括号序列
小w想让分为的这两个括号序列同时合法
小w想知道一共有多少种划分方案
(划分的意思是划分为两个子序列)
注意两个序列是 A,B 和 两个序列是B,A 算两种方案,也就是同一位置位于不同划分为方案不同

输入描述:

第一行一正整数n
第二行,一串长为n的括号序列

输出描述:

一个正整数
表示对方案数对2333取mod后的方案数
示例1

输入

复制
4
(())

输出

复制
6
示例2

输入

复制
8
()()()()

输出

复制
16

备注:

n ≤ 10000

想法:
1 把'('看作是1,')'看作是-1;
2 维护A序列的前缀和 dp[i][k] : 对于在前i个字符中取子序列作为A,其和为k的方法有多少种
💗: k只可以为正,想一想为负的话就会为非法序列
还有假设前i个元素 有k1个'(',和k2个')'; 那么k的取值范围为(0~k1-k2),若'('>k1-k2,就会非法
3对于每一个元素我们有两种选择取或不取
dp[i][k]=dp[i-1][k]+dp[i-1][k-1] str[i]='(';
dp[i][k]=dp[i-1][k]+dp[i-1][k+1] str[i]=')';
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+7;
const int mod=2333;
int dp[2][N];
char str[N];
int n;
int main ()
{
    scanf ("%d %s",&n,str);
    int k=0,top=0;
    dp[0][0]=1;
    for (int i=0;i<n;i++) {
        if (str[i]=='(') {
            top++;
            dp[k^1][0]=dp[k][0];
            for (int j=1;j<=top;j++)
                dp[k^1][j]=(dp[k][j]+dp[k][j-1])%mod;
        }
        else  {
            top--;
            for (int j=0;j<=top;j++)
                dp[k^1][j]=(dp[k][j]+dp[k][j+1])%mod;
        }
        memset (dp[k],0,sizeof(dp[k]));
        k=(k^1);
    }
    printf("%d\n", dp[k][0]);
    return 0;
}