zoukankan      html  css  js  c++  java
  • SP3734 PERIODNI

    题解:

    第一道笛卡尔树dp

    会发现以一个点为分界 如果左边大于它右边大于它 那么大于的那部分是相互不影响的

    于是我们对序列建立笛卡尔树

    满足父亲节点的v<儿子节点的v 然后这棵树的中序遍历为原序列

    这样子我们就可以dp了

    考虑一个矩形的方案数

    $C(n,i)*C(m,i)*i!$ 其中$i!$表示行列自由匹配

    然后现在的话我们只需要统计当前点包含的行数-用掉的 以及 列

    另外处理逆元前缀积有一个比正着递推常数小的方法。。(少了取模和除法运算)

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; int Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    const int N=600;
    const int N1=1e6+100;
    const int N2=1e6;
    const int mo=1e9+7;
    int n,k,v[N],s[N],t,ls[N],rs[N];
    int jc[N1],jc2[N1];
    int dp[N][N],w[N];
    ll tmp[N];
    int ksm(int x,int y)
    {
        if (y==0) return(1);
        if (y==1) return(x);
        int k=ksm(x,y/2);
        k=1ll*k*k%mo;
        if (y%2==1) k=1ll*k*x%mo;
        return k;
    }
    int C(int x,int y)
    {
        if (x<y) return(0);
        return 1ll*jc[x]*jc2[y]%mo*jc2[x-y]%mo;
    }
    void dfs(int x,int y)
    {
        w[x]=1;
        if (ls[x])
        { 
          dfs(ls[x],v[x]); w[x]+=w[ls[x]];
        }
        if (rs[x]) 
        {
          dfs(rs[x],v[x]); w[x]+=w[rs[x]];
        }
        me(tmp);
        rep(i,0,w[x])
        {
          ll y=0;
          rep(j,0,i)
            y+=1ll*dp[ls[x]][j]*dp[rs[x]][i-j]%mo;
          tmp[i]=y%mo;
        }
        rep(i,0,w[x])
          rep(j,0,i)
            (dp[x][i]+=1ll*tmp[j]*C(v[x]-y,i-j)%mo
            *C(w[x]-j,i-j)%mo*jc[i-j]%mo)%=mo;
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout); 
        read(n); read(k);
        int rt;
        rep(i,1,n)
        {
            read(v[i]);
            bool tt=0;
            while (v[i]<v[s[t]]) t--,tt=1;
            rs[s[t]]=i;
            if (tt) ls[i]=s[t+1];
            s[++t]=i;
        }
        rt=rs[0];
        jc[0]=1; jc2[0]=1;
        rep(i,1,N2) jc[i]=1ll*jc[i-1]*i%mo;
        jc2[N2]=ksm(jc[N2],mo-2);
        dep(i,N2-1,1) jc2[i]=1ll*jc2[i+1]*(i+1)%mo;
        dp[0][0]=1;
        dfs(rt,0);
        cout<<dp[rt][k]<<endl;
        return 0;
    }
  • 相关阅读:
    一个程序员的职业规划
    基于Andoird 4.2.2的Account Manager源代码分析学习:创建选定类型的系统帐号
    [置顶] C++学习书单
    js快速分享代码
    The declared package does not match the expected package
    IBM Rational Appscan Part 1
    IBM Rational Appscan: Part 2 ---reference
    阅读redis源代码的一些体会
    18 Command Line Tools to Monitor Linux Performance
    代码规范
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/10038738.html
Copyright © 2011-2022 走看看