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

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

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

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

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N = , mod = 1e9 + ;
  5. int n, K, root;
  6. int H[N], h[N], lc[N], rc[N], w[N];
  7. ll dp[N][N], fac[], f[N][N];
  8. void up(ll &x, const ll &t) { x = (x + t) % mod; }
  9. ll power(ll x, ll t)
  10. {
  11. ll ret = ;
  12. for(; t; t >>= , x = x * x % mod) if(t & ) ret = ret * x % mod;
  13. return ret;
  14. }
  15. ll inv(ll x) { return power(x, mod - ); }
  16. ll C(int a, int b)
  17. {
  18. if(a < b) return ;
  19. return fac[a] * inv(fac[b]) % mod * inv(fac[a - b]) % mod;
  20. }
  21. ll calc(int a, int b, int K)
  22. {
  23. if(a < K || b < K) return ;
  24. ll ret = fac[K] * C(a, K) % mod * C(b, K) % mod;
  25. return ret;
  26. }
  27. void dfs(int u)
  28. {
  29. f[u][] = dp[u][] = ;
  30. if(!u) return;
  31. dfs(lc[u]);
  32. dfs(rc[u]);
  33. for(int i = ; i <= K; ++i)
  34. for(int j = ; j <= i; ++j)
  35. up(f[u][i], dp[lc[u]][j] * dp[rc[u]][i - j] % mod);
  36. for(int i = K; i >= ; --i)
  37. for(int j = ; j <= i; ++j) if(f[u][j])
  38. up(dp[u][i], f[u][j] * calc(H[u], w[u] - j, i - j) % mod);
  39. }
  40. int build(int l, int r)
  41. {
  42. if(l > r) return ;
  43. int p = l;
  44. for(int i = l; i <= r; ++i) if(h[i] < h[p]) p = i;
  45. lc[p] = build(l, p - );
  46. rc[p] = build(p + , r);
  47. H[lc[p]] = h[lc[p]] - h[p];
  48. H[rc[p]] = h[rc[p]] - h[p];
  49. w[p] = r - l + ;
  50. return p;
  51. }
  52. int main()
  53. {
  54. scanf("%d%d", &n, &K);
  55. fac[] = ;
  56. for(int i = ; i <= n; ++i) scanf("%d", &h[i]), H[i] = h[i];
  57. for(int i = ; i <= ; ++i) fac[i] = fac[i - ] * (ll)i % mod;
  58. root = build(, n);
  59. dfs(root);
  60. printf("%lld\n", dp[root][K]);
  61. return ;
  62. }

bzoj2616的更多相关文章

  1. BZOJ2616 SPOJ PERIODNI(笛卡尔树+树形dp)

    考虑建一棵小根堆笛卡尔树,即每次在当前区间中找到最小值,以最小值为界分割区间,由当前最小值所在位置向两边区间最小值所在位置连边,递归建树.那么该笛卡尔树中的一棵子树对应序列的一个连续区间,且根的权值是 ...

  2. 【BZOJ2616】SPOJ PERIODNI 笛卡尔树+树形DP

    [BZOJ2616]SPOJ PERIODNI Description Input 第1行包括两个正整数N,K,表示了棋盘的列数和放的车数. 第2行包含N个正整数,表示了棋盘每列的高度. Output ...

  3. BZOJ2616 : SPOJ PERIODNI

    长为$A$,宽为$B$的矩阵放$K$个车的方案数$=C(A,K)\times C(B,K)\times K!$. 建立笛卡尔树,那么左右儿子独立,设$f[i][j]$表示$i$子树内放$j$个车的方案 ...

  4. bzoj2616: SPOJ PERIODNI——笛卡尔树+DP

    不连续的处理很麻烦 导致序列DP又找不到优秀的子问题 自底向上考虑? 建立小根堆笛卡尔树 每个点的意义是:高度是(自己-father)的横着的极大矩形 子问题具有递归的优秀性质 f[i][j]i为根子 ...

  5. [BZOJ2616]SPOJ PERIODNI 树形dp+组合数+逆元

    2616: SPOJ PERIODNI Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 128  Solved: 48[Submit][Status][ ...

  6. BZOJ2616 SPOJ PERIODNI(笛卡尔树 + DP)

    题意 N,K≤500,h[i]≤106N,K\le 500,h[i]\le10^6N,K≤500,h[i]≤106 题解 建立出小根堆性质的笛卡尔树,于是每个节点可以代表一个矩形,其宽度为子树大小,高 ...

  7. 省选/NOI刷题Day2

    bzoj2616 放一个车的时候相当于剪掉棋盘的一行,于是就可以转移了,中间状态转移dp套dp,推一下即可 bzoj2878 环套树期望dp 手推一下递推式即可 bzoj3295 树状数组套权值线段树 ...

随机推荐

  1. 使用fastJson把对象转字符串首字母大小写问题的解决

    例如:文档中要求传输的字段为 但是转成json字符串后却变成了: 解决方式: 在实体类的get方法上添加@JSONField(name = " ") 注解后问题解决: 输出:

  2. LeetCode第一题以及时间复杂度的计算

    问题描述:给定一组指定整数数组,找出数组中加和等于特定数的两个数. 函数(方法)twoSum返回这两个数的索引,index1必须小于index2. 另外:你可以假设一个数组只有一组解. 一个栗子: I ...

  3. Ubuntu 16.04下快速在当前目录打开终端的快捷键设置

    说明:不一定每次都准确打开,80%的机会是行的. 原理:使用xdotool模拟键盘按键,打开的文件夹管理界面,然后通过Ctrl+L获取地址栏地址,然后传递到终端上. 安装: 1.安装xdotool s ...

  4. openfalcon的安装和使用

    蛮复杂的样子 根据官方文档指导,一步一步走起:https://book.open-falcon.org/zh_0_2/quick_install/prepare.html 单机安装的过程:单击安装会把 ...

  5. 入手Arduino Yun,配合Blynk搞一波事情

    前言 原创文章,转载引用务必注明链接. 最近在闲鱼上与别人用RPi2尸体+好的BBB换了个Arduino Yun,等了几天赶在节前收到了.出奇的轻巧,产地台湾,官方正品做工就是精细~采用5v Micr ...

  6. C#总结复习5(需要进一步复习)

    第十五章 接口 1.接口: C++中允许多继承没有接口的概念.而java与C#中有,因为C#中 是单继承多接口. 所谓的接口,其实和抽象类.方法相似.都只有一个空方法.其本身不可以为基类,但是允许被其 ...

  7. 【转载】图说OOP基础(一)

    本文用图形化的形式描述OOP的相关知识.对OOP进行系统化的梳理,以便掌握. 涉及知识点: OOP的相关知识 OOP知识[Object-Orientation Programming 面向对象编程]总 ...

  8. Linux 用户和文件权限管理

    Linux —— 用户权限管理 权限: 为什么需要权限管理?    1.计算机资源有限,我们需要合理的分配计算机资源.    2.Linux是一个多用户系统,对于每一个用户来说,个人隐私的保护是十分重 ...

  9. 移动Web开发实践

    移动设备的高速发展给用户带来了非常大的便利.用户使用Android.iPhone和其他移动设备非常easy接入互联网. 移动设备对网页的性能要求比較高.以下就说说Mobile Web开发的一些心得. ...

  10. linux块设备驱动(一)——块设备概念介绍

    本文来源于: 1. http://blog.csdn.net/jianchi88/article/details/7212370 2. http://blog.chinaunix.net/uid-27 ...