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 = , mod = 1e9 + ;
int n, K, root;
int H[N], h[N], lc[N], rc[N], w[N];
ll dp[N][N], fac[], f[N][N];
void up(ll &x, const ll &t) { x = (x + t) % mod; }
ll power(ll x, ll t)
{
ll ret = ;
for(; t; t >>= , x = x * x % mod) if(t & ) ret = ret * x % mod;
return ret;
}
ll inv(ll x) { return power(x, mod - ); }
ll C(int a, int b)
{
if(a < b) return ;
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 ;
ll ret = fac[K] * C(a, K) % mod * C(b, K) % mod;
return ret;
}
void dfs(int u)
{
f[u][] = dp[u][] = ;
if(!u) return;
dfs(lc[u]);
dfs(rc[u]);
for(int i = ; i <= K; ++i)
for(int j = ; j <= i; ++j)
up(f[u][i], dp[lc[u]][j] * dp[rc[u]][i - j] % mod);
for(int i = K; i >= ; --i)
for(int j = ; 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 ;
int p = l;
for(int i = l; i <= r; ++i) if(h[i] < h[p]) p = i;
lc[p] = build(l, p - );
rc[p] = build(p + , r);
H[lc[p]] = h[lc[p]] - h[p];
H[rc[p]] = h[rc[p]] - h[p];
w[p] = r - l + ;
return p;
}
int main()
{
scanf("%d%d", &n, &K);
fac[] = ;
for(int i = ; i <= n; ++i) scanf("%d", &h[i]), H[i] = h[i];
for(int i = ; i <= ; ++i) fac[i] = fac[i - ] * (ll)i % mod;
root = build(, n);
dfs(root);
printf("%lld\n", dp[root][K]);
return ;
}
bzoj2616的更多相关文章
- BZOJ2616 SPOJ PERIODNI(笛卡尔树+树形dp)
考虑建一棵小根堆笛卡尔树,即每次在当前区间中找到最小值,以最小值为界分割区间,由当前最小值所在位置向两边区间最小值所在位置连边,递归建树.那么该笛卡尔树中的一棵子树对应序列的一个连续区间,且根的权值是 ...
- 【BZOJ2616】SPOJ PERIODNI 笛卡尔树+树形DP
[BZOJ2616]SPOJ PERIODNI Description Input 第1行包括两个正整数N,K,表示了棋盘的列数和放的车数. 第2行包含N个正整数,表示了棋盘每列的高度. Output ...
- BZOJ2616 : SPOJ PERIODNI
长为$A$,宽为$B$的矩阵放$K$个车的方案数$=C(A,K)\times C(B,K)\times K!$. 建立笛卡尔树,那么左右儿子独立,设$f[i][j]$表示$i$子树内放$j$个车的方案 ...
- bzoj2616: SPOJ PERIODNI——笛卡尔树+DP
不连续的处理很麻烦 导致序列DP又找不到优秀的子问题 自底向上考虑? 建立小根堆笛卡尔树 每个点的意义是:高度是(自己-father)的横着的极大矩形 子问题具有递归的优秀性质 f[i][j]i为根子 ...
- [BZOJ2616]SPOJ PERIODNI 树形dp+组合数+逆元
2616: SPOJ PERIODNI Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 128 Solved: 48[Submit][Status][ ...
- BZOJ2616 SPOJ PERIODNI(笛卡尔树 + DP)
题意 N,K≤500,h[i]≤106N,K\le 500,h[i]\le10^6N,K≤500,h[i]≤106 题解 建立出小根堆性质的笛卡尔树,于是每个节点可以代表一个矩形,其宽度为子树大小,高 ...
- 省选/NOI刷题Day2
bzoj2616 放一个车的时候相当于剪掉棋盘的一行,于是就可以转移了,中间状态转移dp套dp,推一下即可 bzoj2878 环套树期望dp 手推一下递推式即可 bzoj3295 树状数组套权值线段树 ...
随机推荐
- tcp-time-wait-state
https://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux
- Win10激活Office2013的技巧
原文:http://www.xitongzhijia.net/xtjc/20150720/53252.html KMSpico Win10激活工具 是一款能激活Win8/Win8.1/win10/Of ...
- 简单、强大的swig.js
Swig.js A simple, powerful, and extendable JavaScript Template Engine. 简单概括:JS模板引擎. Why to use 根据路劲渲 ...
- 深度神经网络多任务学习(Multi-Task Learning in Deep Neural Networks)
https://cloud.tencent.com/developer/article/1118159 http://ruder.io/multi-task/ https://arxiv.org/ab ...
- PS 如何把大嘴变小嘴
Photoshop整容教程:让MM美唇大嘴变小嘴 2009-06-17 14:15作者:佚名出处:天极网软件频道责任编辑:王健 下面就开始实际操作了. 1.首先从Photosh ...
- 批量修改文件权限 和所有者 chown nobody:nobody * -R chmod 775 * -R
chown nobody:nobody * -R chmod 775 * -R
- goang Receiver & interface
package main import ( "fmt" ) type Pointer struct { x string } func (this *Pointer) PrintX ...
- java开始到熟悉100-102
本次内容:arraylist() 1. package list; import java.util.ArrayList; import java.util.Date; import java.uti ...
- C# 通过比对哈希码判断两个文件内容是否相同
1.使用System.security.Cryptography.HashAlgorithm类为每个文件生成一个哈希码,然后比较两个哈希码是否一致. 2. 在比较文件内容的时候可以采用好几种方法.例如 ...
- android笔记5——同一个Activity中Fragment的切换
今天来模拟一个注冊的界面过程: 点击"下一步"之后: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZW5zb24xNjg1NQ==/f ...