[hdu5181]numbers

题目大意

把1~n顺序入栈,你可以决定出栈序列。
有m组关系,每组关系限制j要在k之前出栈。

DP

首先有个坑点请先判掉,就是存在限制j=k就输出0。。
我们考虑入栈出栈序列。
1入栈,写一个1。
2入栈,写一个2。
3入栈,写一个3。
3出栈,写一个3。
类似这样可以写出一个进出栈序列。
如果我们在最前和最后都加1个0,还可以看做是一个括号序列,也就是一颗以0为根节点的树。
这颗树有以下几个特点:
1、若节点i的子树大小为k,则子树i中的点的编号是[i,i+k-1]。
2、如果i是j的祖先,说明j比i先出栈。
这样的话限制可以转化成子树大小的上下界限制。
我们设f[i,j]表示i子树大小为j,且每一个点都满足限制的方案数。
暂时先不考虑i的限制。
初始f[i,1]=1。
那么有
f[i,j]=j1k=1f[i,jk]f[i+jk][k]
做完这个dp后,我们把非法的子树大小j都来个f[i,j]=0。
最后输出f[0,n+1]即可。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=600+10,mo=1000000007;
int f[maxn][maxn],L[maxn],R[maxn];
int i,j,k,l,t,n,m,ca;
bool czy;
int main(){
    scanf("%d",&ca);
    while (ca--){
        scanf("%d%d",&n,&m);
        czy=0;
        fo(i,0,n) L[i]=0,R[i]=n+1;
        fo(i,1,m){
            scanf("%d%d",&j,&k);
            if (j==k) czy=1;
            if (j<k) R[j]=min(R[j],k-j);
            else L[k]=max(L[k],j-k+1);
        }
        if (czy){
            printf("0\n");
            continue;
        }
        fd(i,n,0){
            fo(j,1,n+1) f[i][j]=0;
            f[i][1]=1;
            fo(j,2,n-i+1)
                fo(k,1,j-1)
                    f[i][j]=(f[i][j]+(ll)f[i][j-k]*f[i+j-k][k]%mo)%mo;
            fo(j,1,L[i]-1) f[i][j]=0;
            fo(j,R[i]+1,n+1) f[i][j]=0;
        }
        printf("%d\n",f[0][n+1]);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值