BZOJ2616PERIODNI
题目描述
给定一个N列的表格,每列的高度各不相同,但底部对齐,然后向表格中填入K个相同的数,填写时要求不能有两个数在同一列,或同一行,下图中b是错误的填写,a是正确的填写,因为两个a虽然在同一行,但它们中间的表格断开。
输出所有填写方案数对1 000 000 007的余数。
输入: 第一行两个整数 N 和 K (1 ≤ N ≤ 500, 1 ≤ K ≤ 500),表示表格的列数和要填写的数的个数。 接下来一行N个数,表示每列的高度。高度不超过 1 000 000.
输出: 一个整数,方案总数对1000 000 007的余数。
题解
这种问题不好在序列上直接处理,考虑每次从当前序列中找出最小的数作为根,递归构造两边的子树。
这样构造出来的数叫笛卡尔树,保证了中序遍历是原序列,整颗树又满足堆的性质。
因为我们需要的树是静态的,所以构建笛卡尔树的复杂度可以降到O(n),具体构建的方法和虚树基本一致,就用栈维护一下当前的右链就可以了。
每次插入节点时一直弹栈,知道弹不动了,就向左连边,否则就连右边。
然后dp就变得十分容易,设dp[i][j]表示i子树内放j个的方案数,注意:我们每往下递归一层,宽度就要减去h[i],这样方便转移。
答案可能来自三部分,左子树、右子树和自己,转移时讨论一下就好了。
代码
#include<iostream>
#include<cstdio>
#define N 502
using namespace std;
const int mod=1e9+;
typedef long long ll;
const int maxn=;
ll dp[N][N],jie[maxn+],ni[maxn+];
int ch[N][],a[N],n,size[N],k,st[N],top;
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline ll power(ll x,ll y){
ll ans=;
while(y){if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;}
return ans;
}
inline ll C(int n,int m){if(n<m)return ;return jie[n]*ni[m]%mod*ni[n-m]%mod;}
void dfs(int u,int fa){
size[u]=;
if(ch[u][])dfs(ch[u][],u),size[u]+=size[ch[u][]];if(ch[u][])dfs(ch[u][],u),size[u]+=size[ch[u][]];
for(int i=;i<=size[u];++i)
for(int j=;j<=i;++j)(dp[u][i]+=dp[ch[u][]][j]*dp[ch[u][]][i-j]%mod)%=mod;
for(int i=size[u];i>=;--i)
for(int j=;j<i;++j)(dp[u][i]+=dp[u][j]*jie[i-j]%mod*C(size[u]-j,i-j)%mod*C(a[u]-a[fa],i-j)%mod)%=mod;
}
int main(){
n=rd();k=rd();
dp[][]=;
for(int i=;i<=n;++i)a[i]=rd();
jie[]=;
for(int i=;i<=maxn;++i)jie[i]=jie[i-]*i%mod;ni[maxn]=power(jie[maxn],mod-);
for(int i=maxn-;i>=;--i)ni[i]=ni[i+]*(i+)%mod;
for(int i=;i<=n;++i){
while(top&&a[i]<a[st[top]]){
int x=st[top];top--;
if(top&&a[i]<a[st[top]])ch[st[top]][]=x;
else ch[i][]=x;
}
st[++top]=i;
}
while(top>){ch[st[top-]][]=st[top];top--;}
dfs(st[],);
printf("%lld",dp[st[]][k]);
return ; }
BZOJ2616PERIODNI的更多相关文章
随机推荐
- Left Jion等价SQL猜想验证
猜想:以下两条SQL等价 select * from A left join B on A.ID=B.BID and B.BName=N'小明' select * from A left join ( ...
- Python 序列化模块(json,pickle,shelve)
json模块 JSON (JavaScript Object Notation):是一个轻量级的数据交换格式模块,受javascript对象文本语法启发,但不属于JavaScript的子集. 常用方法 ...
- JPA之@Transient
java 的transient关键字的作用是需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中. 使用示例: ...
- Centos7安装搭建NTP服务器和NTP客户端同步时间
NTP简介: NTP是网络时间协议(Network Time Protocol),它是用来同步网络中各个计算机的时间的协议. 在计算机的世界里,时间非常地重要 例如:对于火箭发射这种科研活动,对时间的 ...
- LeetCode算法题-Number Complement(Java实现-五种解法)
这是悦乐书的第240次更新,第253篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第107题(顺位题号是476).给定正整数,输出其补码数.补充策略是翻转其二进制表示的位 ...
- CSS伪元素:before/CSS伪元素:before/:after content 显示Font Awesome字体图标:after content 显示Font Awesome字体图标
HTML <a href="javascript:volid(0);"><i class="icon-table"></i> ...
- 10分钟,AppCan帮你搞定跨平台开发APP问题!
跨平台开发APP时,开发者总会遇到一些问题,如打包失败等等,尤其对于iOS来说,由于它的限制性会导致一些状况发生(如证书上传问题等),小编总结了几个AppCan在线IOS打包失败常见的情况及排查技巧, ...
- SegNet 理解与文章结构
SegNet: A Deep Convolutional Encoder-Decoder Architecture for Image Segmentation 发表于2016年,作者 Vijay B ...
- Centos7.x做开机启动脚本
cat /etc/centos-release CentOS Linux release 7.4.1708 (Core) uname -r 3.10.0-693.11.1.el7.x86_64 vim ...
- Python--day03(变量、数据类型、运算符)
day02主要内容回顾 1.语言的分类 -- 机器语言:直接编写0,1指令,直接能被硬件执行 -- 汇编语言:编写助记符(与指令的对应关系),找到对应的指令直接交给硬件执行 -- 高级语言:编写人能识 ...