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的更多相关文章
随机推荐
- 自定义switchButton
这篇博客要讲的是自定义switchButton,不过没有设置动画效果. 我用GradientDrawable来绘制switchButton,我们先看看最终的效果: 点击前: 点击后 接下来我们看看如何 ...
- eclipse开发创建web项目
1.打开eclipse,界面如下: 2.首先配置tomcat,操作:Windows--->perferences 如下: 3.操作:server--->Runtime Environmen ...
- ASP.NET Zero--前端应用程序
前端应用程序 ASP.NET Zero包含可以作为您的公共网站或应用程序着陆页的起点的前端页面.首次运行项目时,您会看到主页如下所示: 这里有两页:主页和关于.这些页面的内容只是占位符和演示目的.您可 ...
- 【原】Java学习笔记004 - 运算符
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 运算符:对常量 或 ...
- 复制命令(ROBOCOPY)
ROBOCOPY 命令: // 描述: 相比较 xcopy.copy 来说,复制的功能就强大很多, xcopy.copy 是单线程的,robocopy是多线程的,但是和一些专业的复制软件相比速度还是 ...
- LNMP构建动态网站WordPress
LNMP构建动态网站wordpress 一.部署LNMP架构 1.安装nginx #配置nginx源 cat>/etc/yum.repos.d/nginx.repo<<-EOF [N ...
- 转 Angular2优质学习资源收集
文档博客书籍类 官方网站: https://angular.io 中文站点: https://angular.cn Victor的blog(Victor是Angular路由模块的作者): https: ...
- TableExistsException: hbase:namespace
解决:zookeeper还保留着上一次的Hbase设置,所以造成了冲突.删除zookeeper信息,重启之后就没问题了 1.切换到zookeeper的bin目录: 2.执行$sh zkCli.sh 输 ...
- kernel笔记——定时器与时间管理
内核中时钟主要完成以下作用: 记录系统运行时间 完成时间相关的统计功能,如cpu占用率等 定时功能,设定某个进程一段时间后完成某项任务 为实现以上功能,硬件以及内核提供了不同类型的时钟. RTC 实时 ...
- redis 初步认识一(下载安装redis)
1.下载redis https://github.com/MicrosoftArchive/redis/releases 2.开启redis服务 3.使用redis 4.redis可视化工具 一 开 ...