SP3734 PERIODNI - 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]='\n';
    }
    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;
}

 

posted @ 2018-11-29 15:42  尹吴潇  阅读(290)  评论(0编辑  收藏  举报