• bzoj2616


    树形dp+笛卡尔树+单调栈

    这道题跟树形dp有什么关系?

    事实上,我们对矩形建立笛卡尔树,先找出最矮的矩形,向两边区间最矮的矩形连边,这样就构成了一棵二叉树,因为只有一个矮的区间会对高的区间造成影响,而且儿子之间不会互相影响,并且这样一层一层保证了每段矩形都会被覆盖到,其实就是单调栈,所以这样连是对的,然后跑一个树形背包,dp[i][j]表示i节点子树放了j个车,很明显两个儿子之间不会互相影响,所以自然是可以合并儿子之间的信息。

    f[u][i]表示自己不放儿子放的方案数,dp[u][i]表示子树里放i个的方案数,然后转移一下就行了。一个 n*m的矩形内放k个的方案数是k!*C(n,k)*C(m,k),选完行和列的交点后全排列表示所有交点。

    #include<bits/stdc++.h>
    using namespace std;    
    typedef long long ll;
    const int N = 505, mod = 1e9 + 7;
    int n, K, root;
    int H[N], h[N], lc[N], rc[N], w[N];
    ll dp[N][N], fac[1000005], f[N][N];
    void up(ll &x, const ll &t) { x = (x + t) % mod; }
    ll power(ll x, ll t)
    {
        ll ret = 1;
        for(; t; t >>= 1, x = x * x % mod) if(t & 1) ret = ret * x % mod;
        return ret;
    }
    ll inv(ll x) { return power(x, mod - 2); }
    ll C(int a, int b) 
    {
        if(a < b) return 0;
        return fac[a] * inv(fac[b]) % mod * inv(fac[a - b]) % mod; 
    }
    ll calc(int a, int b, int K) 
    { 
        if(a < K || b < K) return 0;
        ll ret = fac[K] * C(a, K) % mod * C(b, K) % mod; 
        return ret;
    }
    void dfs(int u)
    {
        f[u][0] = dp[u][0] = 1;
        if(!u) return;
        dfs(lc[u]);
        dfs(rc[u]);
        for(int i = 1; i <= K; ++i)
            for(int j = 0; j <= i; ++j)
                up(f[u][i], dp[lc[u]][j] * dp[rc[u]][i - j] % mod);
        for(int i = K; i >= 1; --i)
            for(int j = 0; j <= i; ++j) if(f[u][j])
                up(dp[u][i], f[u][j] * calc(H[u], w[u] - j, i - j) % mod);
    }
    int build(int l, int r)
    {
        if(l > r) return 0;
        int p = l;
        for(int i = l; i <= r; ++i) if(h[i] < h[p]) p = i;
        lc[p] = build(l, p - 1);
        rc[p] = build(p + 1, r);
        H[lc[p]] = h[lc[p]] - h[p];
        H[rc[p]] = h[rc[p]] - h[p];
        w[p] = r - l + 1;
        return p; 
    }
    int main()
    {
        scanf("%d%d", &n, &K);
        fac[0] = 1;
        for(int i = 1; i <= n; ++i) scanf("%d", &h[i]), H[i] = h[i];
        for(int i = 1; i <= 1000000; ++i) fac[i] = fac[i - 1] * (ll)i % mod;
        root = build(1, n);
        dfs(root);
        printf("%lld
    ", dp[root][K]);
        return 0;
    }
    View Code
  • 相关阅读:
    PCA 主成分分析实践 plink软件
    c语言中基本数据类型
    c语言中利用itoa函数将整数值以二进制、八进制、十六进制显示
    c语言中以10进制、8进制、16进制显示同一个数字
    c语言中实现文件的复制(文本复制和二进制复制)
    c语言 13-13
    c语言显示文件自身
    LYDSY模拟赛day2 Dash Speed
    LYDSY模拟赛day2 Market
    LYDSY模拟赛day2 Divisors
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7760535.html
Copyright © 2020-2023  润新知