比较厉害的dp.

网上题解都是利用了随机的条件,用了一个$O(n^4)$的dp,这里简单说一下。

用f(x,i,l,r)表示经过前i轮操作,[l,r]的所有数<=x,且l-1和r+1都>x的方案数。

转移:f(x,i,l,r)=f(x,i-1,l,r)*g(l,r)+f(x,i-1,j,r)*(j-1)+f(x,i-1,l,k)*(n-k),j<l,k>r

其中,g(l,r)=l*(l-1)/2+(r-l+1)*(r-l+2)/2+(n-r)*(n-r+1)/2

用个前缀和优化一下转移即可。

设h(x,i)表示最终位置i的数<=x的方案数,h(x,i)=$\sum_{l=1}^i\sum_{r=i}^nf(x,q,l,r)$

ans(i)=$\sum_xx*(h(x,i)-h(x-1,i))$

但是这样的做法不够优秀,有没有不利用随机的特性,严格$O(n^3)$的做法呢?

答案是有的。

其实很简单,观察发现转移的时候第一维是固定的,我们可以直接用dp(i,l,r)表示各种x的贡献和。

把上面ans(i)中的h展开,发现dp(i,l,r)=$\sum_x-f(x,i,l,r)$

转移没有变化,但初始化有变化。

初始化时的dp值怎么计算呢?

发现对于一段极长的区间[l,r],dp(0,l,r)=max(a(l)...a(r))-min(a(l-1),a(r+1)),对于非极长的区间dp(0,l,r)=0

发现#define一个for真好用233.

#include <cstdio>
#include <algorithm>
#define F(i,l,r) for(int i=l;i<=r;i++) const int N=,p=1e9+;
int n,q,a[N],f[][N][N],g[N][N],s1[][N][N],s2[][N][N]; int main() {
scanf("%d%d",&n,&q),a[]=a[n+]=1e9+;
F(i,,n) scanf("%d",&a[i]);
F(i,,n) {
int r=;
F(j,i,n) {
g[i][j]=i*(i-)/+(n-j)*(n-j+)/+(j-i+)*(j-i+)/,r=std::max(r,a[j]);
if(i==&&j==n) f[][i][j]=r;
else if(a[i-]>r&&a[j+]>r) f[][i][j]=(r-std::min(a[i-],a[j+])+p)%p;
}
}
F(i,,q) {
int s=i&,t=(i&)^;
F(j,,n) for(int k=n;k>=j;k--) s2[t][j][k]=(s2[t][j][k+]+1LL*f[t][j][k]*(n-k))%p;
F(j,,n) F(k,j,n) s1[t][j][k]=(s1[t][j-][k]+1LL*f[t][j][k]*(j-))%p,f[s][j][k]=(1LL*f[t][j][k]*g[j][k]+s1[t][j-][k]+s2[t][j][k+])%p;
}
F(i,,n) {int a1=; F(j,,i) F(k,i,n) a1=(a1+f[q&][j][k])%p; printf("%d%c",a1," \n"[i==n]);}
return ;
}

BZOJ4574 [Zjoi2016]线段树的更多相关文章

  1. bzoj4574:Zjoi2016线段树 dp

    传送门 题解传送门 //Achen #include<algorithm> #include<iostream> #include<cstring> #includ ...

  2. bzoj 4574: [Zjoi2016]线段树

    Description 小Yuuka遇到了一个题目:有一个序列a_1,a_2,?,a_n,q次操作,每次把一个区间内的数改成区间内的最大值,问 最后每个数是多少.小Yuuka很快地就使用了线段树解决了 ...

  3. 【UOJ#196】【BZOJ4574】[Zjoi2016]线段树

    题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=4574 http://uoj.ac/problem/196 考虑数字随机并且值域够大,我们 ...

  4. Luogu3352 ZJOI2016 线段树 概率、区间DP

    传送门 考虑对于每一个位置\(i\),计算所有可能的结果出现的概率. 定义一个区间\([l,r]\)为对于\(x\)的极大区间,当且仅当\(\max \limits _{i=l}^r \{a_i\} ...

  5. 【ZJOI2016】线段树

    [ZJOI2016]线段树 ZJOI的题神啊. 我们考虑计算每个位置\(p\),它在操作过后变成第\(x\)个数的操作序列数. 我们枚举\(x\).我们先得到了\(L_x,R_x\)表示最左边比\(x ...

  6. @loj - 2093@ 「ZJOI2016」线段树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Yuuka 遇到了一个题目:有一个序列 a1,a2,..., ...

  7. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  8. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  9. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

随机推荐

  1. SQL语句取多列的最小值(排除0)

    经常遇到获取数据表中多个列的最小值和最大值,例如: 获取这 4个价格的最小值和最大值: SELECT( SELECT min(minPrice) FROM ( VALUES (IIF(MarketSi ...

  2. es6+react.js组件入门初探

    React是一个用于构建用户见面的javascript库. React主要用于构建UI,许多人认为React是MVC中的V(视图) React起源于Facebook的内部项目,用来架设Instagra ...

  3. io文本加密

    文本加密习题 package io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Inpu ...

  4. LeetCode & Q53-Maximum Subarray-Easy & 动态规划思路分析

    Array DP Divide and Conquer Description: Find the contiguous subarray within an array (containing at ...

  5. Python内置函数(10)——float

    英文文档: class float([x]) Return a floating point number constructed from a number or string x. If the ...

  6. VMware网络配置

    NAT模式 首先保证虚拟机网卡和主机对接,虚拟机网络连接要和主机在同一网段 1. 控制面板\网络和 Internet\网络连接中配置VMnet8 2. 编辑虚拟机网络配置 此处子网ip需要和Vnet8 ...

  7. 从微软MVP到女儿开学--2017前半年小结

    2017年转眼就到了9月,原本在年初定的计划基本泡汤了. 看书啊减肥啊出教程啊,都被因为各种事物给缠身而没有完成. 1号带女儿去报名的时候,听到老师说"家长们请到这边来集合"的时候 ...

  8. JS笔记(一)

    第一章: 编写JS流程: 1.  布局:HTML和CSS 2.  样式:修改页面元素样式,div的display样式 3.  事件:确定用户做什么操作,onclick(鼠标点击事件).onmouseo ...

  9. 如何在命令行中让python2和python3同存

    初学python,你可能同时安装了python2和3.在我们安装好python之后,我们会面临这样一个问题,在命令行输入"python",可能会出错,或者只能调用其中一个版本,py ...

  10. Java课后练习

    1.利用循环输出:************************* public class Shape { public static void main(String[] args) { for ...