题目描述

给定一个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的更多相关文章

随机推荐

  1. 使用 Browser-solidity 在 Go-Ethereum1.7.2 上进行简单的智能合约部署

    目录 目录 1.基本概念 1.1.什么是智能合约? 1.2.什么是Solidity? 1.2.1.Solidity的语言特性 1.3.什么是 Browser-solidity? 2.Browser-s ...

  2. JHipster生成微服务架构的应用栈(一)- 准备工作

    本系列文章演示如何用JHipster生成一个微服务架构风格的应用栈. 环境需求:安装好JHipster开发环境的CentOS 7.4(参考这里) 应用栈名称:appstack 认证微服务: uaa 业 ...

  3. System.map文件的作用

    有关System.map文件的信息好象很缺乏.其实它一点也不神秘,并且在整个事情当中它并不象看上去那么得重要.但是由于缺乏必要的文档说明,使其显得比较神秘.它就象耳垂,我们每个人都有,但却不知道是干什 ...

  4. 浅谈TCP IP协议栈(四)IP协议解析

    通过之前的网络层基础知识,IP地址以及路由器的简介,大家应该对于TCP/IP有一个大致的了解,在脑海里应该对于网络的几个基础概念有个大概的了解,简单点说整个协议栈就是在做一件事,规定网络报文(网络传输 ...

  5. c/c++ 网络编程 UDP 主机网络信息取得

    网络编程 UDP 主机网络信息取得 1,if_nametoindex 通过网卡名字取得网卡编号 2,if_indextoname 通过网卡编号取得网卡名字 #include <stdio.h&g ...

  6. Unix、Windows、Mac OS、Linux系统故事

    我们熟知的操作系统大概都是windows系列,近年来Apple的成功,让MacOS也逐渐走进普通用户.在服务器领域,恐怕Linux是无人不知无人不晓.他们都是操作系统,也在自己的领域里独领风骚.这都还 ...

  7. WIN提权总结【本地存档-转载】

    [ web提权 ] 1.能不能执行cmd就看这个命令:net user,net不行就用net1,再不行就上传一个net到可写可读目录,执行/c c:\windows\temp\cookies\net1 ...

  8. 认识多线程中start和run方法的区别?

    一.认识多线程中的 start() 和 run() 1.start(): 先来看看Java API中对于该方法的介绍: 使该线程开始执行:Java 虚拟机调用该线程的 run 方法. 结果是两个线程并 ...

  9. eclipse中跳转到其它函数方法后如何快速返回原处

    快捷键 ctrl + 鼠标左键:跳转到引用的方法 alt + left :从所跳转到引用的方法返回原方法 alt + right:从原处返回到引用的方法

  10. 【Python 07】汇率兑换1.0-2(基本元素)

    1.Python基本元素 (1)缩进:表示代码层次关系(Python中表示程序框架唯一手段) 1个tab或者4个空格 (2)注释:开发者加入的说明信息,不被执行.一个代码块一个注释. # 单行注释(一 ...