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] .根 ...
随机推荐
- MySQL搭建主从数据库 实现读写分离
首先声明,实际生产中,网站为了提高用户体验,性能等,将数据库实现读写分离是有必要的,我们让主数据库去写入数据,然后当用户查询的时候,然后在从数据库读取数据,故能减轻数据库的压力,实现良好的用户体验! ...
- 移动端H5活动页优化方案
背景 项目:移动端H5电商项目 痛点:慢!!! 初始方案:最基本的图片懒加载,静态资源放到cdn,predns等等已经都做了.但是还是慢,慢在哪? 显而易见的原因:由于前后端分离,所有的数据都由接口下 ...
- Sudoku 第一步
看到这个问题的思路是先解决生成数独生成器的编写,然后再解决数独求解的问题.最开始第一想法就是暴力求解,仔细算一下复杂度,发现这肯定耗时很久,于是看了很多博客(见转载).我们用回溯搜出来正解.
- Python内置函数(49)——isinstance
英文文档: isinstance(object, classinfo) Return true if the object argument is an instance of the classin ...
- python 判断变量是否是 None 的三种写法
代码中经常会有变量是否为None的判断,有三种主要的写法:第一种是`if x is None`:第二种是 `if not x:`:第三种是`if not x is None`(这句这样理解更清晰`if ...
- python入门(6)输入和输出
python入门(6)输入和输出 输出 >>> print 'hello, world' >>> print 'The quick brown fox', 'jum ...
- java中的引用类型的对象存放在哪里
根据上下文来确定.比如void func(){ Object obj = new Object();//这个obj在函数的栈里.}class Test{ private Object obj ...
- Python之面向对象四
面向对象进阶 一.关于面向对象的两个内置函数 isinstance 判断类与对象的关系 isinstance(obj,cls)检查obj是否是类 cls 的对象,返回值是bool值 issu ...
- UVAlive-2554 Snakes & Ladders---BFS状态的存储
题目链接: https://vjudge.net/problem/UVALive-2554 题目大意: 题目的大概意思是又N*N的棋盘,编号从1 到 N*N 棋盘中分布着蛇和梯子玩家在位置1处, ...
- [翻译] Tensorflow模型的保存与恢复
翻译自:http://cv-tricks.com/tensorflow-tutorial/save-restore-tensorflow-models-quick-complete-tutorial/ ...