【JZOJ5316】【清华集训模拟】merge(DP、括号序)

Description

这里写图片描述

Solution

我们可以想到一个很显然的错误的DP,f[i][j]+=f[i-1][j]+f[i][j-1]
这样明显是会算重的,所以我们要考虑怎样去重。
你可以找一下规律。
我们知道如果在(i,j)前面有一段连续的相同的数的话是会算重的,那么在这之中的转移我们可以强制要求i>=j,那么这个就相当于一个括号序(()()),但是要保证括号影响的连续性,我们需要保证括号外面(…..),如果是从f[i-k][j-k]转移过来的话,那么相当于找2*(k-1)的合法括号序的方案数,那么这个就是卡特兰数。
转移的时候枚举k就好了。枚举k的复杂度最坏情况就是全部相同,枚举次数不会超过n^2。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=4007,mo=1e9+7;
typedef long long ll;
ll i,j,k,l,t,n,m,ans;
ll f[maxn][maxn],a[maxn],b[maxn],g[maxn][maxn],p[maxn][maxn];
ll fact[maxn],ni[maxn];
ll qsm(ll x,ll y){
    ll z=1;
    for(;y;y/=2,x=x*x%mo)if(y&1)z=z*x%mo;
    return z;
}
ll Ca(ll x){
    return fact[2*x]*ni[x]%mo*ni[x]%mo*qsm(x+1,mo-2)%mo;
}
int main(){
    freopen("merge.in","r",stdin);
    freopen("merge.out","w",stdout);
    fact[0]=ni[0]=1;
    fo(i,1,maxn-7)fact[i]=fact[i-1]*i%mo,ni[i]=qsm(fact[i],mo-2);
    scanf("%lld",&n);fo(i,1,n)scanf("%lld",&a[i]);fo(i,1,n)scanf("%lld",&b[i]),f[0][i]=f[i][0]=1;
    f[0][0]=1;
    fo(i,1,n){
        fo(j,1,n){
            if(a[i]==b[j])g[i][j]=g[i-1][j-1]+1;else g[i][j]=0;
            fo(k,1,g[i][j])f[i][j]=(f[i][j]-f[i-k][j-k]*Ca(k-1)%mo)%mo;
            f[i][j]=(f[i][j]+f[i-1][j]+f[i][j-1])%mo;
        }
    }
    printf("%lld\n",f[n][n]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值