题目传送门

Description

作为泉岭精神的缔造者、信奉者、捍卫者、传承者,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条。你能回答出每个询问的最大“主题相关程度”之和么?

\(n,q\le 10^5,L\le 50\)

Solution

这个题在有了提示(知道是分治)之后竟然自己做出来了,这里写一发记录一下。

考虑单次询问怎么做,可以想到,我们可以设 \(f_i\) 表示前面 \(i\) 个数产生的最大贡献,那么我们可以得到转移式:

\[f_i=\max(f_{i-1},f_{i-L}+h_i-h_{i-L})
\]

其中 \(h_{0,1,2,3,...,n}\) 是前缀和。答案就是 \(f_r\)。

考虑优化。因为这个题长度是固定的,所以我们就可以考虑整体操作。

假设我们现在在操作 \([l,r]\),那么,我们现在能更新的答案就是左右端点在 \(mid\) 两侧的,其它的可以继续递归下去。

可以想到的是,在中点两侧的询问一定是要么中间不选要么就是中间选一个(跨界的)区间。因为这个区间长度很小,所以我们就可以预处理出 \(f1_{st,i},f2_{st,i}\) 分别表示从前往后(从后往前)起点在 \(st\),到 \(i\) 这一段产生的贡献,然后枚举一下如果中间选了一个区间的话左边选了多少个以及不选的情况。

复杂度就是 \(\Theta(n\log nL)\),但是因为跑不满所以还是很快的。

Code

#include <bits/stdc++.h>
using namespace std; #define Int register int
#define int long long
#define MAXN 100005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int n,q,len,pre[MAXN],ans[MAXN]; struct node{
int ind,qL,qR;
};
typedef vector<node> poly; #define SZ(A) ((int)A.size())
#define MAXL 55
int f1[MAXL][MAXN],f2[MAXL][MAXN]; void doit1 (int l,int r){//从左往右
for (Int st = 0;st <= len;++ st){
int s = l + st;f1[st][s - 1] = 0;
for (Int i = l;i <= r;++ i)
if (i < s) f1[st][i] = 0;
else{
f1[st][i] = f1[st][i - 1];
if (i - len + 1 >= s) f1[st][i] = max (f1[st][i],f1[st][i - len] + pre[i] - pre[i - len]);
}
}
} void doit2 (int l,int r){
for (Int st = 0;st <= len;++ st){
int s = r - st;f2[st][s + 1] = 0;
for (Int i = r;i >= l;-- i)
if (i > s) f2[st][i] = 0;
else{
f2[st][i] = f2[st][i + 1];
if (i + len - 1 <= s) f2[st][i] = max (f2[st][i],f2[st][i + len] + pre[i + len - 1] - pre[i - 1]);
}
}
}
void chkmx (int &a,int b){a = max (a,b);} void cdq (int l,int r,poly S){
if (l > r || !SZ(S)) return ;
int mid = (l + r) >> 1;doit1 (mid,r),doit2 (l,mid);
poly S1,S2;S1.clear (),S2.clear ();
for (Int i = 0;i < SZ(S);++ i){
if (S[i].qL <= mid && S[i].qR >= mid){
chkmx (ans[S[i].ind],f1[1][S[i].qR] + f2[0][S[i].qL]);
for (Int st = 1;st <= len && mid - st + len <= n && mid - st >= 0;++ st)
if (S[i].qR >= mid + st - 1 && S[i].qL <= mid - (len - st + 1) + 1)
chkmx (ans[S[i].ind],f1[st][S[i].qR] + max (0ll,pre[mid + st - 1] - pre[mid - (len - st + 1)]) + f2[len - st + 1][S[i].qL]);
}
else if (S[i].qR <= mid) S1.push_back (S[i]);
else S2.push_back (S[i]);
}
cdq (l,mid,S1),cdq (mid + 1,r,S2);
} signed main(){
read (n,len);
for (Int i = 1,x;i <= n;++ i) read (x),pre[i] = pre[i - 1] + x;
read (q);poly S;for (Int i = 1;i <= q;++ i){
int l,r;read (l,r);
S.push_back (node {i,l,r});
}
cdq (1,n,S);
for (Int i = 1;i <= q;++ i) write (ans[i]),putchar ('\n');
return 0;
}

题解 「BZOJ3636」教义问答手册的更多相关文章

  1. BZOJ3636: 教义问答手册

    Description “汉中沃野如关中,四五百里烟蒙蒙.黄云连天夏麦熟,水稻漠漠吹秋风.”——摘自 黄裳<汉中行>“泉岭精神不朽,汉中诸球永生.”——摘自<泉岭精神创立者语录> ...

  2. BZOJ 3636 教义问答手册 (分治)

    题意 一个整数数列,多次询问某段区间[li,ri][l_i,r_i][li​,ri​]内,选出若干个长度为LLL且不相交的连续段使选出来的数和最大. 分析 首先想朴素的区间DPDPDP 设f[i][j ...

  3. 题解 「HDU6403」卡片游戏

    link Description 桌面上摊开着一些卡牌,这是她平时很爱玩的一个游戏.如今卡牌还在,她却不在我身边.不知不觉,我翻开了卡牌,回忆起了当时一起玩卡牌的那段时间. 每张卡牌的正面与反面都各有 ...

  4. 题解 「SCOI2016」萌萌哒

    link Description 一个长度为 $ n $ 的大数,用 $ S_1S_2S_3 \ldots S_n $表示,其中 $ S_i $ 表示数的第 $ i $ 位,$ S_1 $ 是数的最高 ...

  5. 题解 「SDOI2017」硬币游戏

    题目传送门 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利. 大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了. 同学们觉得要加强 ...

  6. 题解 「ZJOI2018」历史

    题目传送门 Description 九条可怜是一个热爱阅读的女孩子. 这段时间,她看了一本非常有趣的小说,这本小说的架空世界引起了她的兴趣. 这个世界有 \(n\) 个城市,这 \(n\) 个城市被恰 ...

  7. 题解「BZOJ4310」跳蚤

    题目传送门 Description 现在有一个长度为 \(n\) 的字符串,将其划分为 \(k\) 段,使得这 \(k\) 段每一段的字典序最大子串中字典序最大的字符串字典序尽量小.求出这个字符串. ...

  8. 题解 「BZOJ2137」submultiple

    题目传送门 题目大意 给出 \(M,k\) ,求出 \[\sum_{x|M}\sigma(x)^k \] 给出 \(P_i\),满足 \(n=\prod_{i=1}^{n}a_i^{P_i}\),其中 ...

  9. 题解 「BZOJ2178」圆的面积并

    题目传送门 题目大意 给出 \(n\) 个圆,求它们并的面积大小. \(n\le 10^3\) 思路 如果您不会自适应辛普森法,请戳这里学习 其实我们发现,如果我们设 \(f(x)\) 表示 \(x= ...

随机推荐

  1. Shell脚本逐行读取文本内容并拆分,根据条件筛选文件

    时间:2018-11-13 整理:byzqy 需求: 最近帮朋友写了一段脚本,他的需求是根据一份产品清单,去服务器上捞取对应产品编号的测试Log,数量大概有9000~10000条左右.文本内容大致如下 ...

  2. 【Office Excel】vlookup函数的反向查找实例教程,不只是正向查找,还可以反向查找,实例讲解

    VLOOKUP 反向查询 众所周知,vlookup只能从左向右查找,而不能从右至左的反向查找.为此高手们设计了一个让无数新手迷惑的公式.今天优爱酷将彻底帮同学们解开这个迷团. [例]如下图所示要求根据 ...

  3. Leaflet 操作OSM(OpenStreetMap) 设置地图style

    Leaflet是一个开源的地图操作库,其中mapbox是其一个插件,这个插件可以自定义想要的地图格式.https://www.mapbox.com/mapbox-gl-js/api/这是其官网地址. ...

  4. 菜鸟入门Linux之路(方法论浅谈)

    Linux是为人熟知的OS之王,已"统治"世界.要想学好绝非易事. 作为菜鸟,可以与Linux亲密接触的方法很多,如视频.书籍.各种企培资料等等,如今的在线教育也如火如荼. 总结说 ...

  5. Appium问题解决方案(7)- Could not find 'adb.exe' in PATH. Please set the ANDROID_HOME environment variable with the Android SDK root directory path

    背景:运行代码提示找不到ADB An unknown server-side error occurred while processing the command. Original error: ...

  6. Redis-数据类型-应用场景

    目录 一些小问题 String Hash List Set ZSet BitMaps Hyperloglog Geo Streams 应用场景小结 一些小问题 Redis一共有几种数据类型?(注意是数 ...

  7. JS获取DOM元素的八种方法

    JS获取DOM元素的方法(8种) 通过ID获取(getElementById) 通过name属性(getElementsByName) 通过标签名(getElementsByTagName) 通过类名 ...

  8. logstash-input-jdbc 同时同步多个表的情况

    input { jdbc { jdbc_connection_string => "jdbc:mysql://localhost:3306/crm?zeroDateTimeBehavi ...

  9. 洛谷P1060——开心的金明

    https://www.luogu.org/problem/show?pid=1060 题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间.更让他高兴的是,妈妈 ...

  10. php学习记录,使用script脚本

    echo "<script>alert()</script>"; 原来还能这么用,之前以为echo就是普通的用来打印 同时还可以在script标签下使用lo ...