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,其他人早已停课了,老师估计懒得为我一个人开机房门,让我跟班主任说了一声,今晚就回到了老校,开始了自己都没有想到会来的这么早的停课生 ...
随机推荐
- [PDF] - 获取 RadioButtonList 控件值的方法
背景 目标是通过 iTextSharp 读取 PDF 模板,填充内容后以生成新 PDF 文件.利用 福昕PDF编辑器个人版 可以获取到 RadioButtonList 的组名,但是获取不到每一个 Ra ...
- JVM插码之六:jacoco插码及问题“$jacocodata 属性 Method not found: is$jacocoData”
在使用jacoco统计自动化代码覆盖率 jacoco统计自动化代码覆盖率 1. 简介1.1. 什么是JacocoJacoco是一个开源的代码覆盖率工具,可以嵌入到Ant .Maven中,并提供了Ecl ...
- C++基础(静态数据成员和静态成员函数)
[简介] 1.静态数据成员在类中声明,在源文件中定义并初始化: 2.静态成员函数没有this指针,只能访问静态数据成员: 3.调用静态成员函数:(1)对象.(2)直接调用: 4.静态成员函数的地址可用 ...
- python基础 — CSV 数据处理
什么是csv 逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本) 编码: encode ...
- 03 python 对象笔记
类的命名方法 1.使用大驼峰命名法:每一个单词的首字母大写(第一个的也要)2.单词之间不需要下划线 对象的内置函数和属性 1.使用dir()函数来获取对象的内置方法和属性.返回值是一个列表.2.返回中 ...
- 用mkdocs在gitee码云上建立一个简单的文档博客
利用mkdocs建立简单的文档博客 一.概述 MkDocs 是一个用于创建项目文档的 快速, 简单 , 完美华丽 的静态站点生成器. 文档源码使用 Markdown 来撰写, 用一个 YAML 文件作 ...
- PPPoE中间人拦截以及校园网突破漫谈
本文首发于PPPoE中间人拦截以及校园网突破漫谈,转载请注明出处. PPPoE中间人拦截以及校园网突破漫谈 校园生活快结束了,之前还有点未完成的想法,趁着这两天有兴趣搞搞. 此文面向大众是那种在校园内 ...
- Appium无线连接安卓终端方法 + ADB Shell常用命令(持续更新)
ADB无线连接手机的方法1)手机与PC有线相连 - 检查是否连接正常: adb devices - 执行以下命令:adb tcpip 5555 # 当前9001 - 成功提示:restar ...
- 括号匹配问题 —— Deque双端队列解法
题目: 给定一个只包括 '(',')','{','}','[',']'?的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合.左括号必须以正确的顺序闭合.注意空字符串可 ...
- java -jar 参数前后位置说明
springboot项目启动的时候可以直接使用java -jar xxx.jar这样.下面说说参数的一些讲究 1.-DpropName=propValue的形式携带,要放在-jar参数前面 eg:ja ...