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的更多相关文章
随机推荐
- Redis进阶学习笔记
Redis是什么这里不用再说了吧?下面是官方的解释 Redis is an open source (BSD licensed), in-memory data structure store, us ...
- SQLServer之修改视图
修改视图注意事项 修改先前创建的视图. 其中包括索引视图. ALTER VIEW不影响相关的存储过程或触发器,并且不会更改权限. 如果原来的视图定义是使用 WITH ENCRYPTION 或 CHEC ...
- LSB和MSB
最低有效位(the least significant bit,lsb)是指一个二进制数字中的第0位(即最低位),具有权值为2^0,可以用它来检测数的奇偶性.与之相反的称之为最高有效位.在大端序中,l ...
- Linux PXE无人值守网络装机
Linux PXE无人值守网络装机 一.实验环境: 2台Linux系统(RHEL6.5版本),1台作为:PXE远程安装服务器(安装dhcp服务.ftp服务.tftp服务),另1台作为:客户端(未装RH ...
- centos7防火墙导致不能访问的
CentOS 7.0默认使用的是firewall作为防火墙,使用iptables必须重新设置一下 1.直接关闭防火墙 systemctl stop firewalld.service #停止firew ...
- LNMP构建动态网站WordPress
LNMP构建动态网站wordpress 一.部署LNMP架构 1.安装nginx #配置nginx源 cat>/etc/yum.repos.d/nginx.repo<<-EOF [N ...
- bootatrsp datetimepicker的初始化和阻止模态窗关闭(事件冒泡)
1.github下载资源包 http://www.bootcss.com/p/bootstrap-datetimepicker/ 2.引入bootstrap-datetimepicker.min.c ...
- 《常见排序算法--PHP实现》
原文地址: 本文地址:http://www.cnblogs.com/aiweixiao/p/8202360.html Original 2018-01-02 关注 微信公众号 程序员的文娱情怀 1.概 ...
- C#基础知识之关键字
关键字是 C# 编译器预定义的保留字.这些关键字不能用作标识符,但是,如果您想使用这些关键字作为标识符,可以在关键字前面加上 @ 字符作为前缀.在 C# 中,有些关键字在代码的上下文中有特殊的意义,如 ...
- Kafka 0.11.0.0 实现 producer的Exactly-once 语义(中文)
很高兴地告诉大家,具备新的里程碑意义的功能的Kafka 0.11.x版本(对应 Confluent Platform 3.3)已经release,该版本引入了exactly-once语义,本文阐述的内 ...