BZOJ4574 [Zjoi2016]线段树
比较厉害的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]线段树的更多相关文章
- bzoj4574:Zjoi2016线段树 dp
传送门 题解传送门 //Achen #include<algorithm> #include<iostream> #include<cstring> #includ ...
- bzoj 4574: [Zjoi2016]线段树
Description 小Yuuka遇到了一个题目:有一个序列a_1,a_2,?,a_n,q次操作,每次把一个区间内的数改成区间内的最大值,问 最后每个数是多少.小Yuuka很快地就使用了线段树解决了 ...
- 【UOJ#196】【BZOJ4574】[Zjoi2016]线段树
题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=4574 http://uoj.ac/problem/196 考虑数字随机并且值域够大,我们 ...
- Luogu3352 ZJOI2016 线段树 概率、区间DP
传送门 考虑对于每一个位置\(i\),计算所有可能的结果出现的概率. 定义一个区间\([l,r]\)为对于\(x\)的极大区间,当且仅当\(\max \limits _{i=l}^r \{a_i\} ...
- 【ZJOI2016】线段树
[ZJOI2016]线段树 ZJOI的题神啊. 我们考虑计算每个位置\(p\),它在操作过后变成第\(x\)个数的操作序列数. 我们枚举\(x\).我们先得到了\(L_x,R_x\)表示最左边比\(x ...
- @loj - 2093@ 「ZJOI2016」线段树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Yuuka 遇到了一个题目:有一个序列 a1,a2,..., ...
- bzoj3932--可持久化线段树
题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...
- codevs 1082 线段树练习 3(区间维护)
codevs 1082 线段树练习 3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...
- codevs 1576 最长上升子序列的线段树优化
题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...
随机推荐
- PM2使用心得
PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控.自动重启.负载均衡等,而且使用非常简单. 安装 npm install -g pm2 常用命令 $ npm i ...
- Java中Math类的常用方法
public class MathDemo { public static void main(String args[]){ /** * abs求绝对值 */ System.out.println( ...
- JAVA_SE基础——48.多态
面向对象程序设计的三个特点是封装.继承和多态.前面已经学习了前两个特点.本章节将介绍多态性. 多态:一个对象具备多种形态.(父类的引用类型变量指向了子类的对象)或者是接口 的引用类型变量指向了接口实现 ...
- Python内置函数(62)——exec
英文文档: exec(object[, globals[, locals]]) This function supports dynamic execution of Python code. obj ...
- 【原创】公司各个阶段 CTO 需要做什么?(上篇)
CTO 是企业内技术最高负责人,对企业的发展起到至关重要的作用.但随着公司的不断发展,CTO 的工作重心也会不断变化.只有在正确的阶段做正确的事,才能更好地为公司做出贡献.我是空中金融 CTO ,TG ...
- GIT入门笔记(12)- 删除文件、提交删除和恢复删除
在Git中,删除也是一个修改操作,我们实战一下, 1.先添加add一个新文件test.txt到Git并且提交commit到本地版本库: $ git add test.txt$ git commit - ...
- hadoop2.7.3+spark2.1.0+scala2.12.1环境搭建(1)安装jdk
一.文件准备 下载jdk-8u131-linux-x64.tar.gz 二.工具准备 2.1 Xshell 2.2 Xftp 三.操作步骤 3.1 解压文件: $ tar zxvf jdk-8u131 ...
- python--Selectors模块/队列
Selectors模块/队列 一 Selectors模块 IO多路复用实现机制 Win: select Linux:select(效率低) poll epoll(最好)默认选择epoll sele ...
- 1.5 WEB API 上传文件
1.前提,设置跨域 2.在控制器头添加允许跨域 /// <summary> /// 文件管理口控制器 /// </summary> [EnableCors("*&qu ...
- assert后面如果是假则程序崩溃
assert后面如果是假,则程序崩溃.