合法括号匹配[简单的序列,合法括号匹配]

dp

简单的序列

题解

A过一遍,再做时却错了

真是具有讽刺意味

合法括号匹配

题意

每次可以在末尾加(,),或删除最末位,(长度为0时也可进行删除操作)

问最后合法方案数(长度任意)

 

题解

设$g[i][j]$表示进行i次操作,最终长度为j方案数

最终答案就是$\sum\limits_{i=0}^{i<=n}g[n][i]*catalan()$

模数可能不是质数$n^2$推一下catalan

然而$g$我推挂了

因为我们要求的是长度为j方案,直接的想法是将(,)等效,

$g[i][j]=g[i-1][j-1]+g[i-1][j+1]$

但实际上(,)在删除时是不等效的$[添加时仍是等效的!]$

((删除最末位,()删除最末位最终得到都是(

但这么算就算少了,

$g[i][j]=g[i-1][j-1]+g[i-1][j+1]*2$

这才是这个题要点

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define A 5101
ll f[A][A],g[A][A];
ll n,mod;
int main(){
//    freopen("da.in","r",stdin);
//    freopen("ans.bf","w",stdout);
    scanf("%lld%lld",&n,&mod);
    f[0][0]=1;
    for(ll i=1;i<=n;i++)
        for(ll j=0;j<=i;j++){
            if(j!=0)
                f[i][j]=(f[i-1][j-1]+f[i-1][j+1])%mod;
            else 
                f[i][j]=f[i-1][j+1];
        }
    g[0][0]=1;
    for(ll i=1;i<=n;i++)
        for(ll j=0;j<=i;j++){
            if(j==0)//j==0
                g[i][j]=(g[i-1][j]+g[i-1][j+1]*2)%mod;
            else 
                g[i][j]=(g[i-1][j-1]+g[i-1][j+1]*2)%mod;
        }
    ll ans=0;
    for(ll i=0;i<=n;i++){
//        printf("f[%lld][0]=%lld g[%lld][%lld]=%lld\n",i,f[i][0],n,i,g[n][i]);
        ans=(ans+f[i][0]*g[n][i])%mod;
    }
    printf("%lld\n",ans);
}
View Code

 

posted @ 2019-10-15 14:57  znsbc  阅读(309)  评论(0编辑  收藏  举报