题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2616

把相同高度的连续一段合成一个位置(可能不需要?),用前缀和维护宽度。

然后每次找区间里最低的那个点(ST表)作为根,递归左右孩子,构建笛卡尔树。

dp[ cr ][ j ] 表示在 cr 的子树里选择 j 个点的方案数。

自己本来写的是同时枚举 cr 这个点、ls 、rs 各贡献了多少个车,结果TLE。

看看题解,发现这样比较好(至多 \( n^3 \) ),就是先 \( dp[ cr ][ j ] = \sum dp[ ls ][ k ] * dp[ rs ][ j-k ] ),然后再枚举 cr 的贡献,形如 \( dp[ cr ][ j ] = \sum dp[ cr ][ j-k ] * C_{h}^{k} * C_{w-(j-k)}^{k} * k! \) ,其中 w 表示 cr 这个点的宽,h 表示 cr 这个点的高。

注意那里还要乘一个 \( k! \) 。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int Mn(int a,int b){return a<b?a:b;}
int Mx(int a,int b){return a>b?a:b;} const int N=,K=,M=1e6+,mod=1e9+;
int upt(int x){if(x>=mod)x-=mod;if(x<)x+=mod;return x;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;} int n,ht[N],jc[M],jcn[M],dp[N][N];
int bin[K],lg[N],st[N][K],s[N];
struct Dt{
int bh,mx;
Dt(int b=,int m=):bh(b),mx(m) {}
};
void init(int mx)
{
jc[]=;for(int i=;i<=mx;i++)jc[i]=(ll)jc[i-]*i%mod;
jcn[mx]=pw(jc[mx],mod-);
for(int i=mx-;i>=;i--)jcn[i]=(ll)jcn[i+]*(i+)%mod; for(int i=;i<=n;i++)lg[i]=lg[i>>]+;
bin[]=;for(int i=;i<=lg[n];i++)bin[i]=bin[i-]<<;
for(int i=;i<=n;i++)st[i][]=i;
for(int t=;t<=lg[n];t++)
for(int i=;i+bin[t]-<=n;i++)
{
int u=st[i][t-], v=st[i+bin[t-]][t-];
if(ht[u]<ht[v])st[i][t]=u;
else st[i][t]=v;
}
}
int C(int n,int m)
{
if(n<m)return ;//
return (ll)jc[n]*jcn[m]%mod*jcn[n-m]%mod;
}
int get(int l,int r)
{
int d=lg[r-l+];
int u=st[l][d], v=st[r-bin[d]+][d];
if(ht[u]<ht[v])return u; else return v;
}
Dt solve(int l,int r,int pr)
{
if(l>r)return Dt(,);
int cr=get(l,r), w=s[r]-s[l-], h=ht[cr]-pr;
Dt Ls=solve(l,cr-,ht[cr]); int ls=Ls.bh,m1=Ls.mx;
Dt Rs=solve(cr+,r,ht[cr]); int rs=Rs.bh,m2=Rs.mx;
for(int i=,l1=m1+m2;i<=l1;i++)
for(int j=Mx(,i-m2),l2=Mn(i,m1);j<=l2;j++)
{
dp[cr][i]=(dp[cr][i]+(ll)dp[ls][j]*dp[rs][i-j])%mod;
}
int lm=Mn(h,w), mx=m1+m2+Mn(h,w-m1-m2); dp[cr][]=;
for(int i=mx;i;i--)
for(int j=,l1=Mn(i,lm);j<=l1;j++)
{
dp[cr][i]=(dp[cr][i]+
(ll)dp[cr][i-j]*C(h,j)%mod*C(w-i+j,j)%mod*jc[j])%mod;
}
return Dt(cr,mx);
/*
printf("(%d,%d)cr=%d w=%d h=%d\n",l,r,cr,w,h);
printf(" ls=%d m1=%d rs=%d m2=%d\n",ls,m1,rs,m2);
int mx=m1+m2+Mn(h,w-m1-m2);
printf(" mx=%d\n",mx);
for(int i=1;i<=mx;i++)
{
printf(" i=%d\n",i);
for(int j1=0,l1=Mn(m1,i);j1<=l1;j1++)
for(int j2=Mx(0,i-j1-Mn(h,w-j1)),l2=Mn(i-j1,m2);j2<=l2;j2++)
{
int ret=(ll)dp[ls][j1]*dp[rs][j2]%mod;
int k=i-j1-j2;
ret=(ll)ret*C(h,k)%mod*C(w-j1-j2,k)%mod*jc[k]%mod;//jc[k]
dp[cr][i]=upt(dp[cr][i]+ret);
printf(" j1=%d j2=%d k=%d (dp[%d]=%d)\n"
,j1,j2,k,i,dp[cr][i]);
}
printf(" dp[%d]=%d\n",i,dp[cr][i]);
}
dp[cr][0]=1; return Dt(cr,mx);
*/
}
int main()
{
int tn,tm,mx=;
scanf("%d%d",&tn,&tm);
for(int i=,d,lst=;i<=tn;i++,lst=d)
{
scanf("%d",&d); mx=Mx(mx,d);
if(d!=lst) ht[++n]=d, s[n]=s[n-]+;
else s[n]++;
}
init(mx); dp[][]=;///
Dt Rt=solve(,n,);
printf("%d\n",dp[Rt.bh][tm]);
return ;
}

bzoj 2616 SPOJ PERIODNI——笛卡尔树+树形DP的更多相关文章

  1. BZOJ.2616.SPOJ PERIODNI(笛卡尔树 树形DP)

    BZOJ SPOJ 直观的想法是构建笛卡尔树(每次取最小值位置划分到两边),在树上DP,这样两个儿子的子树是互不影响的. 令\(f[i][j]\)表示第\(i\)个节点,放了\(j\)个车的方案数. ...

  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. 如何合理命名CSS文件——摘自网友

    有经验的网页制作者都明白,对于有多个栏目的大型网站而言,使用单一的CSS文件是不可能的.但CSS文件名如何命名对于新手来说是件容易出乱子的事.如何才能将CSS的命名做得井井有条? 坚持使用统一的CSS ...

  2. memory prefix vice ,with out 1

    1● vice 副的   2● with 向后,相反  

  3. 怎样解决IIS6.0上传文件限制的问题?

    我们用IIS发布的Bs项目,如果进行文件上传,在上传文件的时候,无法上传文件大小超过4M的文件 设置文件上传大小的方法,就是修改项目的web.config配置 在项目中的web.config文件中,添 ...

  4. POJ 2406 KMP 循环节

    给一个字符串.求这个串的最小的循环节的长度. 好像.num = len/(len-next[len]) 就是循环节的长度.如果 len%(len-next[len]) ==0 就是 说字符串长度刚好是 ...

  5. CAS 服务端数据库认证

    CAS-服务端数据库认证 数据认证需要相关的jar包: cas-server-support-jdbc-x.x.x.jar MySQL-connector-Java-x.x.x-bin.jar 修改C ...

  6. RK3288 GMAC整理

    一.源文件 源码路径:\drivers\net\ethernet\rockchip\gmac 源码阅读顺序: 二.重要探针函数stmmac_dvr_probe 1. alloc_etherdev 申请 ...

  7. Jboss7 部署EJB3 简明教程

    什么是EJB? EJB 是 Java 企业Bean, 是JavaEE服务端 企业组件模型,它的设计目标与核心应用是部署分布式应用程序.话不多说,直接看如何在本机部署EJB3.   部署环境: 操作系统 ...

  8. Mysql 存储过程-转载

    存储过程简介 SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储 ...

  9. 通信网络 2G 3G 4G 和路由器2.4G 5G的区分和关系

    通信网络 2G 3G 4G 和路由器2.4G 5G的区分和关系 作者:魔仙圆缘链接:https://www.zhihu.com/question/34076333/answer/57850104来源: ...

  10. jQuery之阻止默认事件以及解除阻止

    大家都知道e.preventDefault()可以阻止默认时间,例如提交功能,但是怎么解除呢?以下参考于网络: 可以使用removeEventListener来移除.但是条件是addEventList ...