description

“汉中沃野如关中,四五百里烟蒙蒙。黄云连天夏麦熟,水稻漠漠吹秋风。”——摘自 黄裳《汉中行》
“泉岭精神不朽,汉中诸球永生。”——摘自《泉岭精神创立者语录》
“把神犇烤一烤,味道会更好。”——摘自《xhr语录》
“秀恩爱有利于身心健康!”——摘自《泉岭精神集大成者语录》
“楼上说的对!”——摘自《泉岭精神信徒语录合集》
“不会做积分,怎么找妹子!”——摘自《xhr语录》
“切实保护耕地以放置更多的哨戒炮。”——摘自《泉岭精神信徒语录合集》
“就算两个包子一起吃掉,也不能阻止我修筑梯田。”——摘自《泉岭精神创立者语录》
“我来自泉岭,他来自汉中,我们半道而逢。”——摘自《泉岭精神集大成者语录》
【问题描述】
作为泉岭精神的缔造者、信奉者、捍卫者、传承者,Pear决定印制一些教义问答手册,以满足泉岭精神日益增多的信徒。Pear收集了一些有关的诗选、语录,其中部分内容摘录在了【题目背景】里。这些语录是按出现的时间排好序的——Pear很喜欢这样的作风,于是决定在按时间排好序的基础上,选择部分语录,制作成若干本教义问答手册。
一共有N条语录。Pear决定从中选出某一段时间内的所有语录,在此基础上印制大小为L的若干本教义问答手册。Pear对印制的手册有如下要求:
1.每本手册必须包含这个区间内连续的恰好L条语录。
2.不同手册包含的语录不能相同。
3.每条语录有一个“主题相关程度”,这个数可正可负。Pear希望所有手册的语录的“主题相关程度”之和尽可能大。
例如,对于区间[3,15]和L=3,一种选择方法是:[4,6]+[9,11]+[12,14]。这三个区间长度都恰好为L,且互不重叠。
Pear并没有决定选哪段时间的语录,因此他有Q次询问。每次询问,给出两个数[l,r]表示候选语录的范围是第l条到第r条。你能回答出每个询问的最大“主题相关程度”之和么?
Input
第一行两个正整数N,L,含义如上所述。注意对于所有询问,L都是一样的。
第二行N个整数,绝对值<=10000。第i个数表示第i条语录的“主题相关程度”。
接下来Q行,每行两个正整数l和r,表示询问区间。
Output
输出Q行,每行表示这组询问的答案。注意,这个答案可以是0,如果区间负数过于多的话。
Sample Input
15 3
3 1 5 -2 3 -2 -2 2 2 2 0 3 2 -1 0
9
8 10
10 10
9 11
2 14
5 14
5 13
12 13
7 13
2 10

Sample Output
6
0
4
17
11
11
0
11
12
Hint

【数据范围】
对于10%的数据,N=1000,Q=1000,L<=50
对于另外20%的数据,N=100000,Q=100000,L<=5
对于另外20%的数据,N=100000,Q=100000,L<=10
对于100%的数据,N=100000,Q=100000,L<=50
Source
2014年国家集训队十五人互测

solution

从最原始的O(n2)O(n^2)O(n2)暴力入手
设f[i][j]f[i][j]f[i][j]表示区间[i,j][i,j][i,j]的答案最大值,sum[i]sum[i]sum[i]表示前缀和
f[i][j]=max(f[i][j−1],f[i][j−L]+sum[j]−sum[j−L])f[i][j]=max(f[i][j-1],f[i][j-L]+sum[j]-sum[j-L])f[i][j]=max(f[i][j−1],f[i][j−L]+sum[j]−sum[j−L])
分治,分界线midmidmid将[l,r][l,r][l,r]分为左右两个区间

  • 长度为LLL的一段完全属于左区间/右区间
  • 跨越了midmidmid在左右区间都有的一段

第一种完全属于某半边区间的就直接分治递归处理
考虑第二种情况,对每一个l′l'l′预处理出在[l′,mid][l',mid][l′,mid]区间选了若干个长度为LLL的区间,且在末尾选了xxx个数的最大值,然后对每一个r′r'r′预处理出在[mid+1,r‘’][mid+1,r‘’][mid+1,r‘’]区间选了若干个长度为LLL的区间,并在开头选了xxx个数的最大值

fl[i][j]fl[i][j]fl[i][j]:以jjj为左端点,左区间末尾选了iii个数的最大值
fr[i][j]fr[i][j]fr[i][j]:以jjj为右端点,右区间开头选了iii个数的最大值

最后询问可以整体二分一并处理

思路好懂,主要是代码细节很ex人

code

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 100005
int n, L, Q;
int p[maxn], ql[maxn], qr[maxn], sum[maxn];//前缀和差分
int fl[55][maxn], fr[55][maxn];
int Left[maxn], Right[maxn], ans[maxn];
//fl[i][j]:以j为左端点 在末尾选了i个数 的最大值
//fr[i][j]:以j为右端点 在开头选了i个数 的最大值
//预处理时的最大值只加了完整L的区间值
void calc_L( int l, int r ) {//对左区间进行预处理 for( int i = 0;i < min( r - l + 1, L );i ++ ) {//枚举跨越mid的在区间末尾选的长度i fl[i][r - i + 1] = 0;for( int j = r - i;j >= l;j -- )//枚举区间的左端点jfl[i][j] = j + L - 1 > r - i ? 0 : max( fl[i][j + 1], fl[i][j + L] + sum[j + L - 1] - sum[j - 1] );//r-i就是不与枚举末尾长度i的起始点相交的第一个点//换言之[r-i+1,r]就是枚举的一个跨越mid的L区间在左半边的部分 //三目运算符判断是否以j为左端点时可以划分出一个完整的在区间的L且不交 (j~j+L-1)}
}
/*
fl[L]:一个跨越mid的长度L区间在左半边就有L个 也就相当于压根没跨越
fr[L]:同理也相当于压根没跨越
此情况恰好与fl[0],fr[0]差了一个L的区间划分循环
故可以由fl[0],fr[0]表示
*/
void calc_R( int l, int r ) {for( int i = 0;i < min( r - l + 1, L );i ++ ) {fr[i][l + i - 1] = 0;//[l,l+i-1]就是枚举的一个跨越mid的L划分区间在右半边的部分 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] + sum[j] - sum[j - L] );//三目运算符判断是否以j为右端点时可以划分出一个完整的在区间的L且不交 (j-L+1~j)}
}void solve( int Ql, int Qr, int l, int r ) {if( Ql > Qr || r - l + 1 < L ) return;int mid = ( l + r ) >> 1;int lenl = 0, lenr = 0;calc_L( l, mid );calc_R( mid + 1, r );for( int i = Ql;i <= Qr;i ++ ) {int id = p[i];if( qr[id] <= mid ) Left[++ lenl] = id;else if( ql[id] > mid ) Right[++ lenr] = id;else {ans[id] = fl[0][ql[id]] + fr[0][qr[id]];//不存在跨越mid的L区间的情况下 最大值//dp动态规划预处理已经做到局部最优解for( int j = max( 1, L - ( qr[id] - mid ) );j <= mid - ql[id] + 1 && j < L;j ++ )ans[id] = max( ans[id], ( mid - j < l ? 0 : fl[j][ql[id]] ) + ( mid + L - j + 1 > r ? 0 : fr[L - j][qr[id]] ) + sum[mid + L - j] - sum[mid - j] );/*mid-j mid+1+L-j都是两边不相交的第一个点ps:注意括号问题 要把三目运算符整个括在一起 不然会错该跨越mid的区间应为 mid-j+1 ~ mid+1 + L-j - 1  枚举跨越mid的L区间的左区间长度j=max(1,L-(qr[id]-mid))保证至少要有1个 且 该区间的右端点抵到整个询问区间的右端点qr[id]mid-ql[id]+1&&j<L保证至多有L-1个这样右边才至少有一个 且 该区间的最多只能抵到整个询问区间的左端点ql[id]判断一下mid-j<l没有因为只预处理了左端点>=l的其余部分应该全为0同理右边判断一下mid+L-j+1>r没有只处理了右端点<=r其余部分应该全为0然后加上跨越的长度为L的区间的a值和但是好像去掉判断也是AC的???不懂了 按道理不能去掉的啊???ans[id] = max( ans[id], fl[j][ql[id]] + fr[L - j][qr[id]] + sum[mid + L - j] - sum[mid - j + 1 - 1] );*/}}for( int i = 1;i <= lenl;i ++ ) p[Ql + i - 1] = Left[i];for( int i = 1;i <= lenr;i ++ ) p[Ql + lenl + i - 1] = Right[i];solve( Ql, Ql + lenl - 1, l, mid );solve( Ql + lenl, Ql + lenl + lenr - 1, mid + 1, r );//注意这里不再是solve(Ql+lenl,Qr,mid+1,r); 进行分类后有一些询问操作是已经处理了的
}int main() {scanf( "%d %d", &n, &L );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &sum[i] );sum[i] += sum[i - 1];}scanf( "%d", &Q );for( int i = 1;i <= Q;i ++ ) {p[i] = i;scanf( "%d %d", &ql[i], &qr[i] );}solve( 1, Q, 1, n );for( int i = 1;i <= Q;i ++ )printf( "%d\n", ans[i] );return 0;
}
//代码参考博客:https://www.cnblogs.com/Orz-IE/p/12039213.html

【BZOJ 3636】教义问答手册 (分治+整体二分+dp)相关推荐

  1. [总结]CDQ分治整体二分

    从昨天到现在除了90%的颓废时间一直在研究一些分治的姿势,主要就是CDQ分治和整体二分. 首先推荐一些学习资料: 陈丹琦 <从 < Cash > 谈一类分治算法的应用> 许昊然 ...

  2. 点分治+CDQ分治+整体二分全纪录

    点分治 点分治讲解 解决树上路径问题 经典例题:点分治(长度小于m的路径计数) 经典例题:点分治(聪聪可可) 经典例题:点分治(多个定值路径计数) 经典例题:点分治(采药) 经典例题:点分治+ST表+ ...

  3. [CDQ分治与整体二分]个人对CDQ分治与整体二分的理解

    在线/离线:首要考虑 在线算法: 可以以序列化的方式一个一个的处理输入,不必事先知道所有输入数据 离线算法: 必须事先知道所有的输入数据 (例如选择排序就是一个离线算法,而插入排序则不是) 众所周知, ...

  4. CDQ 分治与整体二分

    CDQ 分治与整体二分 CDQ 分治 主要是一种分治思想,常用于解决偏序问题. 例如三维偏序问题,我们采用的方法是先处理以第一关键字为区分的左区间.右区间内的答案,再处理左右区间互不干涉的答案. 四维 ...

  5. BZOJ.2738.矩阵乘法(整体二分 二维树状数组)

    题目链接 BZOJ 洛谷 整体二分.把求序列第K小的树状数组改成二维树状数组就行了. 初始答案区间有点大,离散化一下. 因为这题是一开始给点,之后询问,so可以先处理该区间值在l~mid的修改,再处理 ...

  6. BZOJ 2527 Meteors | 整体二分

    BZOJ 2527 Meteors 题意 一个圆环上有m个位置,编号为1~m,分别属于n个国家. 有k个时刻,每个时刻都会给圆环上的一个区间中每个位置的值加上一个数. 每个国家有一个目标,问对于每个国 ...

  7. 【cdq分治】cdq分治与整体二分学习笔记Part2.cdq分治

    上午的学习学会了整体二分,下午学了cdq分治 发现了二者的区别: 整体二分的主体是在不断地二分答案(把所有询问二分),而cdq分治则是在不断地二分操作. 当然同样的,cdq分治的复杂度也是与区间长度正 ...

  8. 【cdq分治】cdq分治与整体二分学习笔记Part1.整体二分

    之所以把cdq分治和整体二分放在一起学习,是因为他们两个实在太像了-不管是做法还是代码- 感觉整体二分可能会比cdq分治稍微简单那么一点点?所以先学整体二分. 整体二分是对答案进行二分,其具体操作如下 ...

  9. cdq分治和整体二分

    cdq分治 ps:先膜拜陈丹琦大神,Orz%%%. 作用 很多动态的题目都需要高级数据结构,代码量很大,这时候cdq分治就展现了它的强大.只要不强制在线,cdq分治就可以将动态转化为静态处理,而且代码 ...

最新文章

  1. Python:PDB文件中原子和残基重新编号
  2. SQL Server查询备份日期和备份设备名
  3. SLAM系统工程,常用数据集下载链接(TUM KITTI DSO Mono EuRoC)
  4. js中的==与===的区别
  5. Java8 stream().map()将对象转换为其他对象
  6. ES6--Let 和 const 命令
  7. 整合Swagger接口文档
  8. Python语言解析xml文件
  9. 维护人员工具_确保丝印机顺畅使用的维护事项有哪些?
  10. .net html第一张图片,基于Asp.net C#实现HTML转图片(网页快照)
  11. 还贷的那些事VI——自由贷的设想
  12. 快速开发微信小程序直播--微信直播--小程序直播开发
  13. 河海大学计算机考研资料汇总
  14. 威纶通定时循环操作宏_武器化excel4.0宏演化过程
  15. springcloud视频教程
  16. 一分钟教你弄懂智能电表的峰、尖、平、谷
  17. 双色球的实现(基于Vuejs)
  18. Windows超级管理器,电脑必备神器,内置超多实用小工具,帮你解决电脑相关问题!
  19. eclipse中转换项目编码时没有GBK的问题
  20. 2021最新 阿里云邮箱域名解析设置要求

热门文章

  1. 《Pyflink》Flink集群安装,Python+Flink调研
  2. java enum优点_你需要关注的 Java Enum 枚举的几个细节
  3. python第k序列元素查找_Python寻找第k小的元素
  4. java 列表展开方式_android列表控件实现展开、收缩功能
  5. 下学期计算机教学工作计划,初中信息技术下学期教学工作计划
  6. android 监听布局改变,Android通过监听最外层布局的改变监听键盘的状态,软键盘的弹出和收起都会改变外层布局(前提是把Activity的mode设置成压缩);...
  7. php 初始二维数组长度,php二维数组排序与默认自然排序的方法介绍
  8. 计算机怎么取消脱敏设置,一种敏感数据自适应的脱敏方法、系统技术方案
  9. java实用教程——组件及事件处理——设置组件的位置(相对于窗口具体位置和布局)
  10. [MyBatisPlus]常用注解_@TableName_@TableId_@TableField_@TableLogic通过全局配置配置主键生成策略