[BZOJ2616]SPOJ PERIODNI 树形dp+组合数+逆元
2616: SPOJ PERIODNI
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 128 Solved: 48
[Submit][Status][Discuss]
Description
.jpg)
Input
第1行包括两个正整数N,K,表示了棋盘的列数和放的车数。
第2行包含N个正整数,表示了棋盘每列的高度。
Output
包括一个非负整数,表示有多少种放置的方案,输出答案mod
1000000007后的结果即可。
Sample Input
2 3 1 2 4
Sample Output
HINT
对于100%的数据,有 N≤500,K≤500,h[i] ≤1000000。
Source
我们可以先构造笛卡尔树(每次找最低点分为两半)
之后设f[i][j]表示以i为根的子树共放了j个的方案数。
每次dp时我们处理g[i]表示左右子树共放了i个的方案数。
长为n,宽为m的矩阵放k个车的方案数为C(n,k)*A(m,k)
依据这个每次枚举g[i]转移f即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define LL long long
#define mod 1000000007
using namespace std;
LL n,k;
LL g[],a[];
LL f[][];
LL p[],inv[];
LL cal(LL x,LL y,LL k){
if(x<k||y<k)return ;
return p[x]*inv[x-k]%mod*inv[k]%mod*p[y]%mod*inv[y-k]%mod;
}
LL dp(int l,int r,int h) {
if(l>r) return ;
int lowi=l;
for(int i=l;i<=r;i++) if(a[lowi]>a[i]) lowi=i;
int la=dp(l,lowi-,a[lowi]),ra=dp(lowi+,r,a[lowi]);
memset(g,,sizeof(g));
for(int i=;i<=lowi-l;i++)
for(int j=;j<=r-lowi;j++) g[i+j]=(g[i+j]+f[la][i]*f[ra][j])%mod;
for(int i=;i<=r-l+;i++)
for(int j=;j<=i;j++)
f[lowi][i]=(f[lowi][i]+g[j]*cal(r-l+-j,a[lowi]-h,i-j))%mod;
return lowi;
}
LL power(LL x,LL ad) {
LL ans=;
while(ad) {
if(ad&) ans=ans*x%mod;
x=x*x%mod;
ad>>=;
}
return ans;
}
int main() {
p[]=;
for(int i=;i<=;i++) p[i]=p[i-]*i%mod;
inv[]=power(p[],mod-);
for(int i=-;i>=;i--)inv[i]=inv[i+]*(i+)%mod;
scanf("%lld%lld",&n,&k);
for(int i=;i<=n;i++) scanf("%lld",&a[i]);
f[][]=;
printf("%lld\n",f[dp(,n,)][k]);
}
[BZOJ2616]SPOJ PERIODNI 树形dp+组合数+逆元的更多相关文章
- BZOJ2616 SPOJ PERIODNI(笛卡尔树+树形dp)
考虑建一棵小根堆笛卡尔树,即每次在当前区间中找到最小值,以最小值为界分割区间,由当前最小值所在位置向两边区间最小值所在位置连边,递归建树.那么该笛卡尔树中的一棵子树对应序列的一个连续区间,且根的权值是 ...
- Codeforces 543D Road Improvement(树形DP + 乘法逆元)
题目大概说给一棵树,树的边一开始都是损坏的,要修复一些边,修复完后要满足各个点到根的路径上最多只有一条坏的边,现在以各个点为根分别求出修复边的方案数,其结果模1000000007. 不难联想到这题和H ...
- bzoj2616: SPOJ PERIODNI——笛卡尔树+DP
不连续的处理很麻烦 导致序列DP又找不到优秀的子问题 自底向上考虑? 建立小根堆笛卡尔树 每个点的意义是:高度是(自己-father)的横着的极大矩形 子问题具有递归的优秀性质 f[i][j]i为根子 ...
- BZOJ2616 SPOJ PERIODNI(笛卡尔树 + DP)
题意 N,K≤500,h[i]≤106N,K\le 500,h[i]\le10^6N,K≤500,h[i]≤106 题解 建立出小根堆性质的笛卡尔树,于是每个节点可以代表一个矩形,其宽度为子树大小,高 ...
- BZOJ2616 : SPOJ PERIODNI
长为$A$,宽为$B$的矩阵放$K$个车的方案数$=C(A,K)\times C(B,K)\times K!$. 建立笛卡尔树,那么左右儿子独立,设$f[i][j]$表示$i$子树内放$j$个车的方案 ...
- [BZOJ4824][Cqoi2017]老C的键盘 树形dp+组合数
4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 218 Solved: 171[Submit][Statu ...
- 【BZOJ2616】SPOJ PERIODNI 笛卡尔树+树形DP
[BZOJ2616]SPOJ PERIODNI Description Input 第1行包括两个正整数N,K,表示了棋盘的列数和放的车数. 第2行包含N个正整数,表示了棋盘每列的高度. Output ...
- 5.10 省选模拟赛 tree 树形dp 逆元
LINK:tree 整场比赛看起来最不可做 确是最简单的题目. 感觉很难写 不过单独考虑某个点 容易想到树形dp的状态. 设f[x]表示以x为根的子树内有黑边的方案数. 白边方案只有一种所以不用记录. ...
- SPOJ 1435 - Vertex Cover(树形DP,树的最小点覆盖)
算是个经典题目了,很模板的树形DP题目 做这个题的时候一开始就想到树形DP了,可是由于各种原因没写出来,代码太糟烂了,赛后还是改了好久才过的 dp(u,0)=sum(dp(v,1)): dp(u,1) ...
随机推荐
- github如何添加新的分支
需求:甲建立分支分给乙步骤:在甲创建的项目仓库里边点右上角的按钮 就可以通过名字搜索了. 在乙的右上角 再选中Repositories就可以看到所有的 存储库 了
- SPOJ6340 ZUMA - ZUMA
题意:n个珠子排成一排,都有各自的颜色. 你可以选择不少于w个连续同色的珠子消掉,也可以先放着.你还可以任意插入任意颜色的珠子. 求全部消掉至少要插入几个珠子. 解: 什么毒瘤东西...... 有个十 ...
- Go(02)windows环境搭建和vscode配置
之前讲述过linux环境下Go语言开发环境搭建,这次简述下windows的搭建以及vscode配置 windows环境搭建 同样去https://studygolang.com/dl下载windows ...
- freemark+ITextRenderer 生成PDF,设置pdf的页面大小
在html中添加样式,仅生成pdf是生效,浏览器展示时是不会生效的: <style> @page{ size : 200mm 300 mm; } </style>
- AngularJs分层结构小demo
后端mvc分层,前端也要分层才对嘛.分层的好处不言而喻.简直太清晰,容易维护.反正清爽的一逼.不信你看. 思路:分为controller层和service层.controller层再提取一个公共的层. ...
- html5 canvas从圆开始
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- [机器学习&数据挖掘]SVM---软间隔最大化
根据上个硬间隔最大化已经知道,在解决线性可分数据集的分类问题时,求得拉格朗日乘子.w.b就得到分离超平面,然后就可以进行分类,软间隔最大化是针对非线性可分的数据集,因为并不是数据集在可分的时候会出现一 ...
- 20155318 2016-2017-2 《Java程序设计》第五周学习总结
20155318 2016-2017-2 <Java程序设计>第五周学习总结 教材学习内容总结 try...catch 键盘输入利用java.util.Scanner,Scanner 名 ...
- Value = undefined
Value = undefined Javascript在计算机程序中,经常会声明无值的变量.未使用值来声明的变量,其值实际上是 undefined. 在执行过以下语句后,变量 carname 的值将 ...
- 使用js获取浏览器地址栏里的参数
用JS获取地址栏参数的方法(超级简单) 方法一:采用正则表达式获取地址栏参数:( 强烈推荐,既实用又方便!) function GetQueryString(name) { var reg = new ...