BZOJ 3636 教义问答手册 (分治)
题意
一个整数数列,多次询问某段区间[li,ri][l_i,r_i][li,ri]内,选出若干个长度为LLL且不相交的连续段使选出来的数和最大。
分析
首先想朴素的区间DPDPDP
设f[i][j]f[i][j]f[i][j]表示区间[i,j][i,j][i,j]的答案。O(n2)O(n^2)O(n2)转移比较显然。
f[i][j]=max(f[i][j−1],f[i][j−L]+∑k=j−L+1ja[j])f[i][j]=max(f[i][j-1],f[i][j-L]+\sum_{k=j-L+1}^ja[j])f[i][j]=max(f[i][j−1],f[i][j−L]+k=j−L+1∑ja[j])
为了方便我们把∑k=j−L+1ja[j]\sum_{k=j-L+1}^ja[j]∑k=j−L+1ja[j]记作b[j]b[j]b[j],则
f[i][j]=max(f[i][j−1],f[i][j−L]+b[j])f[i][j]=max(f[i][j-1],f[i][j-L]+b[j])f[i][j]=max(f[i][j−1],f[i][j−L]+b[j])
空间和时间都会爆。然后想想多组询问怎么做。
发现L≤50L\le50L≤50,于是就有巧妙的分治做法。
对于区间[qL,qR][qL,qR][qL,qR],中点是midmidmid。我们把跨越midmidmid的询问拿出来求答案,没有跨越的分治下去,就变成了子问题。
那么对于一个询问[qL,qR][qL,qR][qL,qR],它的答案有两种情况。
- 一种是没有选跨越midmidmid的连续段,那么就是[qL,mid][qL,mid][qL,mid]和[mid+1,qR][mid+1,qR][mid+1,qR]的答案加起来。
- 另一种是跨越了midmidmid的。因为LLL很小我们枚举跨越midmidmid的一段在左边有多长,记作jjj,则右边长为L−jL-jL−j。那么有1<j<L,1<L−j<L1<j<L,1<L-j<L1<j<L,1<L−j<L。
那么答案就是[qL,mid−j][qL,mid-j][qL,mid−j]的答案加上[mid+1+L−j,qR][mid+1+L-j,qR][mid+1+L−j,qR]的答案再加上中间一段的答案b[mid+L−j]b[mid+L-j]b[mid+L−j]
发现上面需要算答案的区间只有O(nL)O(nL)O(nL)级别的且连续,可以直接预处理。
然后就做完了。时间复杂度O(nLlogn)O(nL\log n)O(nLlogn)。具体实现见代码。
CODE
#include <bits/stdc++.h>
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void rd(int &x) {
x = 0; char ch; int flg=1; while(!isdigit(ch=getc()))if(ch=='-')flg=-flg;
do x=x*10+ch-'0'; while(isdigit(ch=getc())); x *= flg;
}
const int MAXN = 100005;
const int MAXL = 55;
int n, m, L, a[MAXN], ans[MAXN];
struct query { int l, r, id; }q[MAXN], tmp1[MAXN], tmp2[MAXN];
int fL[MAXL][MAXN], fR[MAXL][MAXN];
inline void workL(int l, int r) {
for(int i = 0; i <= r-l && i < L; ++i) {
fL[i][r-i+1] = 0;
for(int j = r-i; j >= l; --j)
fL[i][j] = j+L-1 > r-i ? 0 : max(fL[i][j+1], fL[i][j+L] + a[j+L-1]);
}
}
inline void workR(int l, int r) {
for(int i = 0; i <= r-l && i < L; ++i) {
fR[i][l+i-1] = 0;
for(int j = l+i; j <= r; ++j)
fR[i][j] = j-L+1 < l+i ? 0 : max(fR[i][j-1], fR[i][j-L] + a[j]);
}
}
void cdq(int l, int r, int ql, int qr) {
if(ql > qr || r-l+1 < L) return;
int mid = (l + r) >> 1, it1 = 0, it2 = 0;
workL(l, mid); workR(mid+1, r);
for(int i = ql; i <= qr; ++i) {
if(q[i].r <= mid) tmp1[++it1] = q[i];
else if(q[i].l > mid) tmp2[++it2] = q[i];
else {
ans[q[i].id] = fL[0][q[i].l] + fR[0][q[i].r];
for(int j = max(1, L-(q[i].r-mid)); j <= mid-q[i].l+1 && j < L; ++j)
ans[q[i].id] = max(ans[q[i].id], (mid-j < l ? 0 : fL[j][q[i].l]) + (mid+L-j+1 > r ? 0 : fR[L-j][q[i].r]) + a[mid+L-j]);
}
}
for(int i = 1; i <= it1; ++i) q[ql+i-1] = tmp1[i];
for(int i = 1; i <= it2; ++i) q[ql+it1+i-1] = tmp2[i];
cdq(l, mid, ql, ql+it1-1); cdq(mid+1, r, ql+it1, ql+it1+it2-1);
}
int main () {
rd(n), rd(L);
for(int i = 1; i <= n; ++i) rd(a[i]), a[i] += a[i-1];
for(int i = n; i >= L; --i) a[i] -= a[i-L];
rd(m);
for(int i = 1; i <= m; ++i) rd(q[i].l), rd(q[i].r), q[i].id = i;
cdq(1, n, 1, m);
for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
}
BZOJ 3636 教义问答手册 (分治)的更多相关文章
- BZOJ3636: 教义问答手册
Description “汉中沃野如关中,四五百里烟蒙蒙.黄云连天夏麦熟,水稻漠漠吹秋风.”——摘自 黄裳<汉中行>“泉岭精神不朽,汉中诸球永生.”——摘自<泉岭精神创立者语录> ...
- 题解 「BZOJ3636」教义问答手册
题目传送门 Description 作为泉岭精神的缔造者.信奉者.捍卫者.传承者,Pear决定印制一些教义问答手册,以满足泉岭精神日益增多的信徒.Pear收集了一些有关的诗选.语录,其中部分内容摘录在 ...
- BZOJ.4184.shallot(线段树分治 线性基)
BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...
- [BZOJ 4025]二分图(线段树分治+带边权并查集)
[BZOJ 4025]二分图(线段树分治+带边权并查集) 题面 给出一个n个点m条边的图,每条边会在时间s到t出现,问每个时间的图是否为一个二分图 \(n,m,\max(t_i) \leq 10^5\ ...
- BZOJ.4320.[ShangHai2006]Homework(根号分治 分块)
BZOJ \(\mathbb{mod}\)一个数\(y\)的最小值,可以考虑枚举剩余系,也就是枚举区间\([0,y),[y,2y),[2y,3y)...\)中的最小值(求后缀最小值也一样)更新答案,复 ...
- BZOJ 1176 [Balkan2007]Mokia ——CDQ分治
[题目分析] 同BZOJ2683,只需要提前处理s对结果的影响即可. CDQ的思路还是很清晰的. 排序解决一维, 分治时间, 树状数组解决一维. 复杂度是两个log [代码] #include < ...
- BZOJ 2683 简单题 ——CDQ分治
[题目分析] 感觉CDQ分治和整体二分有着很本质的区别. 为什么还有许多人把他们放在一起,也许是因为代码很像吧. CDQ分治最重要的是加入了时间对答案的影响,x,y,t三个条件. 排序解决了x ,分治 ...
- BZOJ 3365 Distance Statistics 点分治
这道题是一道点分治的题目,难度不大,可以拿来练手. 关键是对于找出来的重心的删除操作需要删掉这条边,这很重要. 还有每次找重心的时候,不但要考虑他的子节点的siz,还要考虑父节点的siz. 然后就A了 ...
- 【BZOJ 1468】Tree 点分治
点分治$O(nlogn)$ 坚持到月考结束后新校就剩下我一个OIer,其他人早已停课了,老师估计懒得为我一个人开机房门,让我跟班主任说了一声,今晚就回到了老校,开始了自己都没有想到会来的这么早的停课生 ...
随机推荐
- 016 Android 图片选择器(在选中和未选中的过程中,切换展示图片)
1.目标效果 在选中和未选中的过程中,切换展示图片 2.实现方法 (1)在app--->res--->drawable 右击drawable文件夹右键,new ---->drawab ...
- Java基础笔试练习(二)
1. HashMap的数据结构是怎样的? A.数组 B.链表 C.数组+链表 D.二叉树 答案: C 解析: JDK8以后,HashMap的数据结构是数组+链表+红黑树 2. 在 JAVA 编程中,J ...
- Qt4 和 Qt5 模块的分类
Qt5 与 Qt4 其中的一个区别是底层架构进行了改变,Qt5 引入了更加详细的模块化的概念,将众多功能细分到几个模块之中,Qt4 则是一种粗略的划分.本文主要对 Qt5 和 Qt4的模块进行一个简单 ...
- SpinWait 第二篇
SpinWait 提供了两个方法和两个只读属性. 方法: SpinWait.Reset() : 重置自旋计数器,将计数器置 0.效果就好像没调用过SpinOnce一样.SpinWait.Once() ...
- VBA switch语句
当用户想要根据Expression的值执行一组语句时,使用Switch Case语句. 每个值被称为一个”情况”,并根据每种情况变量接通测试.如果测试表达式与用户指定的任何Case不匹配,则执行Cas ...
- ubuntu16.04环境下在docker上部署javaweb项目简单案例
因为一些原因,接触到了docker,经过一番研究,总算是有了一些自己的看法,有什么不对的地方,希望多多指教. 废话不多说,首先我这里使用的虚拟机安装的是ubuntu16.04版本,其他版本应该也可以. ...
- textarea与标签组合,点击标签填入标签内容,再次点击删除内容(vue)
需求:将textarea与span标签组合,点击标签自动填入标签文本内容,再次点击删除标签文本对应内容 原理:点击标签时,将标签内容作为参数,将内容拼接在textarea的value后面,再次点击标签 ...
- vue实现一个评论列表
<!DOCTYPE html> <html> <head> <title>简易评论列表</title> <meta charset=& ...
- JS如何做爬虫
JS如何做爬虫,JS做爬虫要靠node节点环境,cheerio(主要是解析下载的网页可以像jquery一样,这是必要的,使用它在npm上查看文档也很简单). Iconv-lite(主要解决下载资源的乱 ...
- 关于http的小知识
http客户端发起请求,创建端口 http服务器在端口监听客户端请求 http服务器向客户端返回状态和内容 浏览器: 1.Chrome搜索自身的DNS缓存 2.搜索操作系统自身的DNS缓存(浏览器没有 ...