• 计数(count)


    计数(count)

    题目描述

    既然是萌萌哒 visit_world 的比赛,那必然会有一道计数题啦!

    考虑一个 NN个节点的二叉树,它的节点被标上了 1∼N1∼N 的编号. 并且,编号为 ii的节点在二叉树的前序遍历中恰好是第ii个出现.

    我们定义AiAi 表示编号为ii的点在二叉树的中序遍历中出现的位置.

    现在,给出MM个限制条件,第ii个限制条件给出了ui,viui,vi,表示Aui<AviAui<Avi ,也即中序遍历中uiuivivi 之前出现.

    你需要计算有多少种不同的带标号二叉树满足上述全部限制条件,答案对109+7109+7 取模.

    输入

    第一行一个整数 T(1≤T≤5)T(1≤T≤5), 表示数据组数.

    每组数据第一行为两个整数 N,MN,M,意义如题目所述.

    接下来 MM 行,每行两个整数ui,vi(1≤ui,vi≤N)ui,vi(1≤ui,vi≤N) . 描述一条限制.

    输出

    对每组数据,输出一行一个整数,表示答案.

    样例输入

    3
    5 0
    3 2
    1 2
    2 3
    3 3
    1 2
    2 3
    3 1

    样例输出

    1

    提示

    解释

    第一组数据,无任何限制时,5 个点的二叉树形态个数为 4242 .

    第二组数据,唯一满足条件的二叉树的形态为 1 - 2 - 3.(1 为根,2, 3 均为右儿子).

    第三组数据,限制条件产生矛盾.

    样例 2

    见下发文件.

    数据范围和子任务

    对于全部的测试数据,保证 T≤5,N≤400,M≤103T≤5,N≤400,M≤103 .

    子任务 1(20 分):M=0M=0 .

    子任务 2(15 分):N≤10N≤10 .

    子任务 3(20 分):N≤50,M≤1N≤50,M≤1 .

    子任务 4(15 分):N≤50N≤50 .

    子任务 5(30 分):无特殊限制.

    来源

    hnsdfz国庆集训day2


    solution

    20分是卡特兰数 然后我打崩了

    令f[i][j]表示先序遍历序号为i~j的组成的树有多少种不同形态

    那么 if(合法) f[i][j]=f[i+1][k]+f[k+1][j] 

    我们考虑怎么判断一个点是否合法

    那么

    1  [i+1,k]的任何一个点中序遍历都不能在[k+1,j] 以后

    2  [i+1,k]的任何一个点中序遍历都不能在i以后

    3  i的中序遍历都不能在[k+1,j] 以后

    区间对区间可以用二维前缀和优化

    效率O(n^3)

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 405
    #define mod 1000000007
    #define ll long long
    using namespace std;
    int T,n,m,t1,t2;
    ll f[maxn][maxn],s[maxn][maxn],a[maxn][maxn];
    void init(){
        for(int i=0;i<=400;i++)
        for(int j=0;j<=400;j++)f[i][j]=s[i][j]=a[i][j]=0;
    }
    int calc(int x,int y,int xx,int yy){
        return s[xx][yy]-s[xx][y-1]-s[x-1][yy]+s[x-1][y-1];
    }
    bool pd(int ii,int xa,int xb,int ya,int yb){
        if(calc(ya,xa,yb,xb))return 0;
        if(calc(ya,ii,yb,ii))return 0;
        if(calc(ii,xa,ii,xb))return 0;
        return 1;
    }
    int main()
    {
        cin>>T;
        while(T--){
            init();
            cin>>n>>m;
            for(int i=1;i<=m;i++){
                scanf("%d%d",&t1,&t2);
                a[t1][t2]=1;
            }
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++)s[i][j]=a[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1];
            }
            for(int i=1;i<=n;i++)f[i][i]=1;
            for(int l=1;l<=n;l++){
            for(int i=1;i+l<=n;i++){
                int j=i+l;
                if(!calc(i,i+1,i,j))f[i][j]+=f[i+1][j];
                if(!calc(i+1,i,j,i))f[i][j]+=f[i+1][j];
                for(int k=i+1;k<j;k++){
                    if(pd(i,i+1,k,k+1,j)){
                        f[i][j]+=f[i+1][k]*f[k+1][j];
                         
                    }
                 
                    f[i][j]%=mod;
                }
              }
            }
            cout<<f[1][n]<<endl;
        }
        return 0;
    }
     
  • 相关阅读:
    iPhone 上利用MKMapView实现简单地图的方法
    项目经理:做好项目开始阶段的九条经验(1) 项目 技术应用
    iPhone的Push(推送通知)功能原理浅析
    iPhone拍照/摄像软件开发实例
    每位开发人员都应铭记的10句编程谚语
    注册itunes 中国区app Store账号详细步骤
    [转载]:各位技术牛人和应届毕业生,外企是唯一的选择吗?
    [推荐] IT外企那点儿事(1):外企也就那么回事[
    CheckBox全选与不全选(不用刷新页面)
    CheckBox的全选与不全选(刷新页面效果) .
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358819.html
Copyright © 2020-2023  润新知