BZOJ

SPOJ


直观的想法是构建笛卡尔树(每次取最小值位置划分到两边),在树上DP,这样两个儿子的子树是互不影响的。

令\(f[i][j]\)表示第\(i\)个节点,放了\(j\)个车的方案数。

设\(v\)是\(i\)的一个儿子,对于子树部分的转移,有$$f'[i][j]=\sum_{k\leq j}f[v][j-k]f[i][k]$$

求完子树贡献后,对于\(i\)节点代表的矩形,设高度是\(h\)宽度是\(w\),有$$f'[i][j]=\sum_{k\leq j}f[i][j-k]\cdot k!C_hkC_{w-j+k}k$$

然后就ok啦。复杂度是\(O(n^2k)\)。(所以建笛卡尔树可以暴力\(n^2\))

\(O(n)\)建笛卡尔树,就是维护一个单调栈,栈中元素是当前树最右边的一条链。


//9636kb	516ms
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define mod 1000000007
#define Mod(x) x>=mod&&(x-=mod)
#define C(n,m) (1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod)//n<m
#define gc() getchar()
typedef long long LL;
const int N=504,M=1e6+5;
const LL LIM=5e18; int m,h[N],sk[N],fa[N],son[N][2],f[N][N],fac[M],ifac[M];//M!!! inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
inline int FP(int x,int k)
{
int t=1;
for(; k; k>>=1,x=1ll*x*x%mod)
if(k&1) t=1ll*t*x%mod;
return t;
}
int DFS(int x)
{
static int g[N];
if(!x) return 0;
// f[x][0]=1;
// for(int i=0; i<2; ++i)
// if(son[x][i])
// {
// int v=son[x][i],szv=DFS(v);
// for(int j=0,v1; j<=sz; ++j)
// if((v1=f[x][j]))
// for(int k=0,v2; k<=szv&&j+k<=m; ++k)
// if((v2=f[v][k]))
// g[j+k]+=1ll*v1*v2%mod, Mod(g[j+k]);
// sz+=szv;
// for(int j=std::min(sz,m); ~j; --j) f[x][j]=g[j], g[j]=0;
// }
int ls=son[x][0],rs=son[x][1],a=DFS(ls),b=DFS(rs),m=::m;
for(int i=0,v1; i<=a; ++i)
if((v1=f[ls][i]))
for(int j=0,v2; j<=b&&i+j<=m; ++j)
if((v2=f[rs][j]))
f[x][i+j]+=1ll*v1*v2%mod, Mod(f[x][i+j]);
int h=::h[x]-::h[fa[x]],w=a+b+1;//sz
for(int i=std::min(w,m); ~i; --i)
{
LL tmp=0;
for(int j=0; j<=i&&j<=h; ++j) tmp+=1ll*f[x][i-j]*fac[j]%mod*C(h,j)%mod*C(w-i+j,j), tmp>=LIM&&(tmp%=mod);
f[x][i]=tmp%mod;
}
return w;
} int main()
{
int n=read(),m=read(),mx=n; ::m=m;//mx=max(hi,n)!
for(int i=1; i<=n; ++i) mx=std::max(mx,h[i]=read()); fac[0]=1;
for(int i=1; i<=mx; ++i) fac[i]=1ll*fac[i-1]*i%mod;
ifac[mx]=FP(fac[mx],mod-2);
for(int i=mx; i; --i) ifac[i-1]=1ll*ifac[i]*i%mod; int top=0; h[sk[0]=0]=0;//设成-1要改回来啊mdzz(dfs用到h[fa[root]])
for(int i=1; i<=n; ++i)
{
while(h[sk[top]]>h[i])
{
int a=sk[top--];
if(h[sk[top]]>h[i]) son[fa[a]=sk[top]][1]=a;
else son[fa[a]=i][0]=a;
}
sk[++top]=i;
}
while(top>1) fa[sk[top]]=sk[top-1], son[sk[top-1]][1]=sk[top], --top;
int root=sk[1];
f[0][0]=1, DFS(root), printf("%d\n",f[root][m]); return 0;
}

BZOJ.2616.SPOJ PERIODNI(笛卡尔树 树形DP)的更多相关文章

  1. bzoj 2616 SPOJ PERIODNI——笛卡尔树+树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2616 把相同高度的连续一段合成一个位置(可能不需要?),用前缀和维护宽度. 然后每次找区间里 ...

  2. 【BZOJ2616】SPOJ PERIODNI 笛卡尔树+树形DP

    [BZOJ2616]SPOJ PERIODNI Description Input 第1行包括两个正整数N,K,表示了棋盘的列数和放的车数. 第2行包含N个正整数,表示了棋盘每列的高度. Output ...

  3. BZOJ2616 SPOJ PERIODNI(笛卡尔树+树形dp)

    考虑建一棵小根堆笛卡尔树,即每次在当前区间中找到最小值,以最小值为界分割区间,由当前最小值所在位置向两边区间最小值所在位置连边,递归建树.那么该笛卡尔树中的一棵子树对应序列的一个连续区间,且根的权值是 ...

  4. bzoj2616: SPOJ PERIODNI——笛卡尔树+DP

    不连续的处理很麻烦 导致序列DP又找不到优秀的子问题 自底向上考虑? 建立小根堆笛卡尔树 每个点的意义是:高度是(自己-father)的横着的极大矩形 子问题具有递归的优秀性质 f[i][j]i为根子 ...

  5. BZOJ.3611.[HEOI2014]大工程(虚树 树形DP)

    题目链接 要求的和.最大值.最小值好像都可以通过O(n)的树形DP做,总询问点数<=2n. 于是建虚树就可以了.具体DP见DP()函数,维护三个值sum[],mx[],mn[]. sum[]要开 ...

  6. BZOJ 2286 [Sdoi2011]消耗战(虚树+树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2286 [题目大意] 出一棵边权树,每次给出一些关键点,求最小边割集, 使得1点与各个关 ...

  7. BZOJ.5287.[AHOI HNOI2018]毒瘤(虚树 树形DP)

    BZOJ LOJ 洛谷 设\(f[i][0/1]\)表示到第\(i\)个点,不选/选这个点的方案数.对于一棵树,有:\[f[x][0]=\prod_{v\in son[x]}(f[v][0]+f[v] ...

  8. bzoj 1040: [ZJOI2008]骑士【基环树+树形dp】

    没考虑可以连着两个不选--直接染色了 实际上是基环森林,对于每棵基环树,dfs找出一个环边,然后断掉这条边,分别对这条边的两端点做一边treedp,取max加进答案里 treedp是设f[u]为选u点 ...

  9. BZOJ2616 SPOJ PERIODNI(笛卡尔树 + DP)

    题意 N,K≤500,h[i]≤106N,K\le 500,h[i]\le10^6N,K≤500,h[i]≤106 题解 建立出小根堆性质的笛卡尔树,于是每个节点可以代表一个矩形,其宽度为子树大小,高 ...

随机推荐

  1. visual studio 不能跳转到函数定义

    解决办法: 工具-->扩展和更新-->联机.搜索“Go To Definition”下载然后关闭visualstudio进行安装,重启后就ok了

  2. P2518 [HAOI2010]计数

    题目链接 \(Click\) \(Here\) 很好很妙的一个题目. 其实可以生成的数字,一定是原数的一个排列,因为\(0\)被放在前面就可以认为不存在了嘛~.也就是说现在求的就是全排列中所有小于该数 ...

  3. GO语言系列(二)- 基本数据类型和操作符

    一.文件名 & 关键字 & 标识符 1.所有go源码以.go结尾 2.标识符以字母或下划线开头,大小写敏感 3._是特殊标识符,用来忽略结果 4.保留关键字 二.Go程序的基本结构 p ...

  4. Kubernetes之Pod 控制器

    定义Pod的常用资源 pods.spec.containers - name    <string>   #containers 的名字 image    <string>  ...

  5. CentOS7部署Dotnet Core2.1

    前言 笔者在毫无Linux部署.net core的经验下,第一次用了15分钟完成部署,第二次在生产环境用了5分钟.下文将说明如何在CentOS7下完成.NetCore2.1的部署,包括如何创建ASP. ...

  6. 第六节:SignalR完结篇之依赖注入和分布式部署

    一. SignalR中DI思想的应用 DI,即依赖注入,它是一种不负责创建其自己的依赖项对象的一种模式,通常用来降低代码之间的耦合性,广泛应用于架构设计,是必不可少的一种思想. 下面结合一个需求来说一 ...

  7. 第十节: 利用SQLServer实现Quartz的持久化和双机热备的集群模式 :

    背景: 默认情况下,Quartz.Net作业是持久化在内存中的,即 quartz.jobStore.type = "Quartz.Simpl.RAMJobStore, Quartz" ...

  8. ArcGis安装失败提示“需要Microsoft .NET Framework 3.5 sp1或等效环境”的解决方法

    这个问题一般出现在Win8或者Win10系统上,因为系统默认没有启用该.Net Framework. 下载Microsoft .NET Framework 3.5 sp1安装后再开始安装ArcGis. ...

  9. [物理学与PDEs]第4章第1节 引言

    1.  本章讨论可燃流体在流动过程中同时伴随着燃烧现象的情况. 2.  燃烧有两种, 一种是爆燃 (deflagration): 火焰低速向前传播, 此时流体微元通常是未燃气体.已燃气体的混合物; 一 ...

  10. metasploit 教程之基本参数和扫描

    前言 首先我也不知道我目前的水平适不适合学习msf. 在了解一些msf之后,反正就是挺想学的.就写博记录一下.如有错误的地方,欢迎各位大佬指正. 感激不尽.! 我理解的msf msf全程metaspl ...