码迷,mamicode.com
首页 > 其他好文 > 详细

SP3734 PERIODNI - Periodni 笛卡尔树 DP

时间:2021-03-05 13:29:19      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:read   top   ret   spl   get   lld   include   begin   its   

题意:

戳这里

分析:

一看到是直方图的题目,我们可以联想到笛卡尔树

我们将列数作为 BST 的一维,将高度作为小根堆的一维,这样笛卡尔树上每一个节点都是一个矩形

我们考虑在矩形中选出 k 个合法点的方案数,显然等价于 \(C_{wid}^kC_{hig}^kk!\) ,表示选出 k 种高度和下标并配对,且点之间有标号

然后我们在笛卡尔树上DP,设 \(f_{i,j}\) 表示节点 \(i\) 所代表的子树内选了 \(j\) 个点的方案,转移方程如下:

\[\begin{cases} f_{u,i}=f_{u,i}+f_{v,j}*f_{u,i-j} (子树向父亲贡献) \f_{u,i}=f_{u,i}+f_{u,i-j}*C_{siz-(i-j)}^jC_{hig}^j*j!(选择自己代表的矩形) \end{cases} \]

代码:

#include<bits/stdc++.h>
#define inl inline
#define reg register

using namespace std;

namespace zzc
{
    typedef long long ll;
    inl ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch==‘-‘)f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const ll mod = 1e9+7;
    const ll maxn = 505;
    const ll maxm = 1e6+5;
    ll n,k,top;
    ll ch[maxn][2],a[maxn],st[maxn],f[maxn][maxn],fac[maxm],inv[maxm],wid[maxn],siz[maxn];

    void init()
    {
        fac[0]=fac[1]=1;
        inv[0]=inv[1]=1;
        for(reg ll i=2;i<=1000000;i++) fac[i]=fac[i-1]*i%mod,inv[i]=inv[mod%i]*(mod-mod/i)%mod;
        for(reg ll i=2;i<=1000000;i++) inv[i]=inv[i]*inv[i-1]%mod;
    }

    ll C(ll n,ll m)
    {
        if(n<m) return 0;
        return fac[n]*inv[n-m]%mod*inv[m]%mod;
    }

    void dfs(ll u,ll hig)
    {
        hig=a[u]-hig;
        f[u][0]=1;siz[u]=1;
        for(reg ll t=0;t<=1;t++)
        {
            if(!ch[u][t]) continue;
            dfs(ch[u][t],a[u]);
            siz[u]+=siz[ch[u][t]];
            for(reg ll i=min(siz[u],k);i>=0;i--) 
                for(reg ll j=1;j<=min(siz[ch[u][t]],i);j++) 
                    f[u][i]=(f[u][i]+f[u][i-j]*f[ch[u][t]][j]%mod)%mod;
        }
        for(reg ll i=min(siz[u],k);i>=0;i--)
            for(reg ll j=1;j<=min(hig,i);j++)
                f[u][i]=(f[u][i]+f[u][i-j]*C(siz[u]-(i-j),j)%mod*C(hig,j)%mod*fac[j]%mod)%mod;
    }

    void work()
    {
        init();
        n=read();k=read();
        for(reg ll i=1;i<=n;i++) a[i]=read();
        for(reg ll i=1;i<=n;i++)
        {
            ll j=top;
            while(j&&a[st[j]]>a[i]) j--;
            if(j) ch[st[j]][1]=i;
            if(j<top) ch[i][0]=st[j+1];
            top=j;st[++top]=i;
        }
        dfs(st[1],0);
        printf("%lld\n",f[st[1]][k]);
    }
}

int main()
{
    zzc::work();
    return 0;
}

SP3734 PERIODNI - Periodni 笛卡尔树 DP

标签:read   top   ret   spl   get   lld   include   begin   its   

原文地址:https://www.cnblogs.com/youth518/p/14485171.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!