Codeforces 1107G Vasya and Maximum Profit 线段树最大子段和 + 单调栈
Codeforces 1107G 线段树最大子段和 + 单调栈
G. Vasya and Maximum Profit
Description:
Vasya got really tired of these credits (from problem F) and now wants to earn the money himself! He decided to make a contest to gain a profit.
Vasya has \(n\) problems to choose from. They are numbered from \(1\) to \(n\). The difficulty of the \(i\)-th problem is \(d_i\). Moreover, the problems are given in the increasing order by their difficulties. The difficulties of all tasks are pairwise distinct. In order to add the \(i\)-th problem to the contest you need to pay \(c_i\) burles to its author. For each problem in the contest Vasya gets \(a\) burles.
In order to create a contest he needs to choose a consecutive subsegment of tasks.
So the total earnings for the contest are calculated as follows:
if Vasya takes problem \(i\) to the contest, he needs to pay \(c_i\) to its author; for each problem in the contest Vasya gets \(a\) burles; let \(gap(l, r) = \max\limits_{l \le i < r} (d_{i + 1} - d_i)^2\). If Vasya takes all the tasks with indices from \(l\) to \(r\) to the contest, he also needs to pay \(gap(l, r)\). If \(l = r\) then \(gap(l, r) = 0\). Calculate the maximum profit that Vasya can earn by taking a consecutive segment of tasks.
Input:
The first line contains two integers \(n\) and \(a\) (\(1 \le n \le 3 \cdot 10^5\), \(1 \le a \le 10^9\)) — the number of proposed tasks and the profit for a single problem, respectively.
Each of the next \(n\) lines contains two integers \(d_i\) and \(c_i\) (\(1 \le d_i, c_i \le 10^9, d_i < d_{i+1}\)).
Output
Print one integer — maximum amount of burles Vasya can earn.
Sample Input:
5 10
1 15
5 3
6 11
7 2
11 22
Sample Output:
13
Sample Input:
3 5
1 8
2 19
3 11
Sample Output:
0
题目链接
题解:
你现在有一个题库,里面有\(n\)道题,每道题难度为\(d_i\), 保证\(d_i\)严格单调增,你现在需要从中选择出一个连续子段的题来组成一场比赛,比赛每有一道题你能获得\(a\)的收益,但需要给作者支付\(c_i\)的费用,除此以外,你还需要支付相邻两道题的难度的差值的平方的最大值的费用(可能题目难度跨度过大会引起不满233)
形式话的说,如果你选择了\(l\)到\(r\)的题目,最后总收益为\(a \cdot (r-l+1)-\sum_l^rc_i-\max\limits_{l\le i\lt r}(d[i+1]-d[i])^2\), 特别地如果\(l=r\),则第三项为0
首先考虑前两项,显然每道题的收益为\(a-c_i\),如果没有第三项那就是一个最大子段和问题
现在考虑第三项,设\(diff[i] = d[i + 1] - d[i]\),只有\(n-1\)项,考虑这\(n-1\)项分别作为最大值的的区间,就是左边下标最大的比它大的和右边下标最小的比它大的中间的区间即为\(diff[i]\)作为最大值的区间,这个可以用单调栈\(O(n)\)处理出来,然后用线段树跑\(n-1\)次最大子段和就行了,总复杂度为\(O(nlog(n))\)
ps:这里有一个问题,就是对于\(diff[i]\)跑最大子段和时跑出来的区间不一定包含\(i\),但这题不是问题,因为要减去\(diff[i]^2\),不包含的话只会获得更小的值(设该区间\(diff\)最大值为\(diff[j]\),显然\(diff[j] \le diff[i]\),在处理以\(diff[j]\)为最大值的区间时可以获得更大的收益),如果一定要包含那就线段树改成询问\(l\)到\(i\)的包含右端点的最大值和\(i+1\)到\(r\)的包含左端点的最大值(可以为空)加起来就行了
pps:还有就是整场比赛只有一道题(没有\(diff\)),直接\(O(n)\)处理出来就行了
AC代码:
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 3e5 + 10;
struct tree {
LL sum, rmx, lmx, mx;
}sgt[N << 2];
int c[N], d[N], diff[N], a, n, l[N], r[N];
long long ans;
void pushup(int rt) {
sgt[rt].sum = sgt[rt << 1].sum + sgt[rt << 1 | 1].sum;
sgt[rt].mx = max(sgt[rt << 1].mx, sgt[rt << 1 | 1].mx);
sgt[rt].lmx = max(sgt[rt << 1].lmx, sgt[rt << 1].sum + sgt[rt << 1 | 1].lmx);
sgt[rt].rmx = max(sgt[rt << 1 | 1].rmx, sgt[rt << 1 | 1].sum + sgt[rt << 1].rmx);
sgt[rt].mx = max(sgt[rt].mx, sgt[rt << 1].rmx + sgt[rt << 1 | 1].lmx);
}
void build(int rt, int l, int r) {
if(l == r) {
sgt[rt].sum = sgt[rt].lmx = sgt[rt].rmx = sgt[rt].mx = c[l];
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
tree query(int rt, int l, int r, int L, int R) {
if(L <= l && r <= R) return sgt[rt];
int mid = l + r >> 1;
if(R <= mid) return query(rt << 1, l, mid, L, R);
if(L > mid) return query(rt << 1 | 1, mid + 1, r, L, R);
tree u = query(rt << 1, l, mid, L, R), v = query(rt << 1 | 1, mid + 1, r, L, R), o;
o.sum = u.sum + v.sum;
o.mx = max(u.mx, v.mx);
o.mx = max(o.mx, u.rmx + v.lmx);
o.lmx = max(u.lmx, u.sum + v.lmx);
o.rmx = max(v.rmx, v.sum + u.rmx);
return o;
}
struct node {
int val, id;
};
int main() {
scanf("%d %d", &n, &a);
for(int i = 1; i <= n; ++i) {
scanf("%d%d", &d[i], &c[i]);
c[i] = a - c[i];
ans = max(ans, 1LL * c[i]);
}
for(int i = 1; i < n; ++i)
diff[i] = d[i + 1] - d[i];
build(1, 1, n);
stack<node> stk;
stk.push({(int)1e9, 0});
for(int i = 1; i < n; ++i) {
while(stk.top().val <= diff[i])
stk.pop();
l[i] = stk.top().id + 1;
stk.push({diff[i], i});
}
while(!stk.empty()) stk.pop();
stk.push({(int)1e9, n});
for(int i = n - 1; i; --i) {
while(stk.top().val <= diff[i])
stk.pop();
r[i] = stk.top().id;
stk.push({diff[i], i});
}
for(int i = 1; i < n; ++i) {
ans = max(ans, query(1, 1, n, l[i], r[i]).mx - 1LL * diff[i] * diff[i]);
}
printf("%lld\n", ans);
return 0;
}
Codeforces 1107G Vasya and Maximum Profit 线段树最大子段和 + 单调栈的更多相关文章
- [Educational Round 59][Codeforces 1107G. Vasya and Maximum Profit]
咸鱼了好久...出来冒个泡_(:з」∠)_ 题目连接:1107G - Vasya and Maximum Profit 题目大意:给出\(n,a\)以及长度为\(n\)的数组\(c_i\)和长度为\( ...
- CodeForces 1107 - G Vasya and Maximum Profit 线段树
题目传送门 题解: 枚举 r 的位置. 线段树每个叶子节点存的是对应的位置到当前位置的价值. 每次往右边移动一个r的话,那么改变的信息有2个信息: 1. sum(a-ci) 2.gap(l, r) 对 ...
- Codeforces 1107G Vasya and Maximum Profit [单调栈]
洛谷 Codeforces 我竟然能在有生之年踩标算. 思路 首先考虑暴力:枚举左右端点直接计算. 考虑记录\(sum_x=\sum_{i=1}^x c_i\),设选\([l,r]\)时那个奇怪东西的 ...
- Codeforces 1383E - Strange Operation(线段树优化 DP or 单调栈+DP)
Codeforces 题目传送门 & 洛谷题目传送门 Yet another 自己搞出来的难度 \(\ge 2800\) 的题 介绍一个奇奇怪怪的 \(n\log n\) 的做法.首先特判掉字 ...
- Codeforces 487B Strip (ST表+线段树维护DP 或 单调队列优化DP)
题目链接 Strip 题意 把一个数列分成连续的$k$段,要求满足每一段内的元素最大值和最小值的差值不超过$s$, 同时每一段内的元素个数要大于等于$l$, 求$k$的最小值. 考虑$DP$ 设$ ...
- [Codeforces 266E]More Queries to Array...(线段树+二项式定理)
[Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...
- [Codeforces 280D]k-Maximum Subsequence Sum(线段树)
[Codeforces 280D]k-Maximum Subsequence Sum(线段树) 题面 给出一个序列,序列里面的数有正有负,有两种操作 1.单点修改 2.区间查询,在区间中选出至多k个不 ...
- codeforces 1217E E. Sum Queries? (线段树
codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...
- AcWing:245. 你能回答这些问题吗(线段树最大子段和)
给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一: 1.“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 maxx≤l≤r≤ymaxx≤l≤r≤y{∑ri=lA[i]∑i=l ...
随机推荐
- 模仿jquery框架源码---网络
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Untitled Page& ...
- Effective java -- 9 并发/序列化
关于同步的问题,想弄明白java,同步不会是不行的.这不书弄完后还会从<java并发编程实战>和<java并发编程的艺术>选一本或者都看. 第六十六条:同步访问共享的可变数据说 ...
- IAR 条件断点
条件断点是IDE的一个重要功能,在IAR调试时候,经常跟踪一个数据,但是对较大的buffer,用普通的断点或live watch都不好跟踪. 比如某个buffer里一个数,我们知道他在第几个,但是却从 ...
- POJ3614 贪心+优先队列
题意:m头牛每头牛有minspf和maxspf,n种spf为spf[i]的防晒霜每种l[i]瓶,尽可能给数量多的牛涂防晒霜,每头牛最多涂一瓶. 思路:贪心想法,实现是每次取出minspf<=sp ...
- Luogu-3829 [SHOI2012]信用卡凸包
这道题的转化很巧妙,可以把信用卡四个角的圆心看做平面上的点来做凸包,\(ans\)就是凸包周长加上一个圆的周长 // luogu-judger-enable-o2 #include<cmath& ...
- Spark- SparkStreaming可更新状态的实例
Producer package zx.zx.sparkkafka import java.util.Properties import kafka.producer.{KeyedMessage, P ...
- [SQL类] SQL优化大全(推荐)
概要 优化的理由 1. 大小写对SQL语句的影响(ORACLE) 2. 尽量使用(NOT) EXISTS 替代( NOT)IN这样的操作 3. 在海量查询时尽量少用格式转换 4. 查询海量数据是,可以 ...
- Java企业微信开发_02_通讯录同步
一.本节要点 1.获取通讯录密钥 获取方式: 登录企业微信—>管理工具—>通讯录同步助手—>开启“API接口同步” ; 开启后,即可看到通讯录密钥,也可设置通讯录API的权限:读取 ...
- 前端多媒体(7)—— 在浏览器中实现rtmp推流
示例:https://young-cowboy.github.io/gallery/rtmp_client/index.html 在国内的直播场景中通常使用,rtmp协议作为推流协议.RTMP是Rea ...
- 判断CPU是大端还是小端
#include "stdafx.h" #include <iostream> using namespace std; /* #大端模式(Big_endian):字数 ...