[机房测试]括号匹配

Description

给出长度为 n 的括号序列(只包含小括号和中括号),问有多少种方法删掉这些括号的一个子集,使得剩下的括号序列是合法的,请注意不能全部删完。

Solution

写了三道题,只拍了这题,结果就这题没挂,真的服了。

考虑到一个合法的括号串是若干个单串拼接起来的,所以可以考虑通过这个来转移。fl,r 表示区间 [l,r] 的合法串个数,gl,r 表示左端点是 l,右端点在 [l,r] 的合法单串个数。(为什么要保证左端点必须是 l?因为我们转移是通过枚举断点转移,钦定最后一段的端点就能保证不会算重)

fl,r=i=lr(fl,i1+1)×gi,rgl,r=i=l+1r[SlSi](fl+1,i1+1)

#include<stdio.h>
#include<string.h>

const int N=3e2+7;
const int Mod=1e9+7;

char s[N];
int g[N][N],f[N][N];

inline void Add(int &x,int y){
    x+=y; if(x>=Mod) x-=Mod;
}

inline int op(char x){
    if(x=='(') return 0;
    if(x=='[') return 1;
    if(x==']') return 2;
    if(x==')') return 3;
}

int Dfs(int,int);
int dfs(int,int);

int Dfs(int l,int r){
    if(l>=r) return 0;
    int &ret=g[l][r];
    if(~ret) return ret; else ret=0;
    if(op(s[l])>=2) return 0;
    for(int i=l+1;i<=r;i++)
        if(op(s[l])+op(s[i])==3) Add(ret,dfs(l+1,i-1)+1);
    return ret;
}

int dfs(int l,int r){
    if(l>=r) return 0;
    int &ret=f[l][r];
    if(~ret) return ret; else ret=0;
    for(int i=l;i<r;i++) Add(ret,Dfs(i,r));
    for(int i=l+1;i<=r;i++)
        Add(ret,1ll*dfs(l,i)*Dfs(i+1,r)%Mod);
    return ret;
}

int main(){
    freopen("parenthesis.in","r",stdin);
    freopen("parenthesis.out","w",stdout);
    int n; scanf("%d",&n);
    scanf("%s",s+1);
    memset(g,-1,sizeof(g));
    memset(f,-1,sizeof(f));
    printf("%d",dfs(1,n));
//    for(int l=1;l<=n;l++)
//        for(int r=l;r<=n;r++)
//            printf("[%d,%d] %d %d\n",l,r,dfs(l,r),Dfs(l,r));
}

/*
30
[(]))][(][((([[])()]])[([])))]

6 ()()[]

21
[](]]([))()][[[][(()]
*/
posted @   Kreap  阅读(39)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示