Luo's oj P1916 简单的序列(bracket)

传送门

分析

我们将左括号看作 1,右括号看作 -1,则一个合法的括号序列需要满足:
*所有括号的总和为 0
*每个前缀和均不小于0
我们先统计出串 s 的总和 a 以及最小的前缀和 b,然后枚举串 p 的长度 i 以及总和 j, 考虑到需要满足第二个条件,那么 j 需要满足 j+b>=0。记 f[ i ][ j ] 为长度为 i ,总和为 j 的括号序列数量,此时 p 的方案数为 f[ i ][ j ]q 的方案数为 f[ n - m - i ][ j + a ],将它们的乘积计入答案即可。
f 可以通过一个简单的 DP 求出,时空复杂度均为 O((n-m)^2)

#include<bits/stdc++.h>
#define ll long long
#define N 100005
#define M 2005
#define mod 1000000007
using namespace std;
int n,m,k,u,ans,f[M][M];
char s[N];
int main(){
    scanf("%d%d",&n,&m);
    scanf("%s",s+1);
    for(int i=1;i<=m;i++){
        u+=s[i]=='(' ? 1:-1;
        k=min(k,u);
    }
    f[0][0]=1;
    for(int i=1;i<=n-m;i++)
        for(int j=0;j<=i;j++){
            f[i][j]=0;
            if(j>0)f[i][j]=(f[i][j]+f[i-1][j-1])%mod;
            if(j<i-1)f[i][j]=(f[i][j]+f[i-1][j+1])%mod;
        }
    for(int i=-k;i<=n-m;i++)
        for(int j=-k;j<=i;j++)
            if(u+j<=n-m-i) ans=(ans+(ll)f[i][j]*f[n-m-i][u+j])%mod;
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值