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 ...
随机推荐
- 创建图形用户界面GUI和事件监听机制的简单实现(java)
创建图形化界面 1.创建Frame窗体 2.对窗体进行基本设置 比如:大小.位置.布局 3.定义组件 4.将组建通过窗体添加到窗体中 5.让窗体显示,通过setVisib ...
- Java多线程系列 JUC线程池06 线程池原理解析(五)
ScheduledThreadPoolExecutor解析 ScheduledThreadPoolExecutor适用于延时执行,或者周期性执行的任务调度,ScheduledThreadPoolExe ...
- leetcode 901. Online Stock Span
Write a class StockSpanner which collects daily price quotes for some stock, and returns the span of ...
- python 3 并发编程多进程 paramiko 模块
python 3 paramiko模块 paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的pa ...
- 手机端适配rem代码片段
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 前端框架之VUE
vue学习[第1篇]:vue之指令 vue学习[第2篇]:es6简单介绍 vue学习[第3篇]:vue之node.js的简单介绍 vue学习[第4篇]:vue 之webpack打包工具的使用 vue学 ...
- yield生成器的经典案例
如何生成斐波那契數列 斐波那契(Fibonacci)數列是一个非常简单的递归数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到.用计算机程序输出斐波那契數列的前 N 个数是一个非常简单的问题 ...
- 前端多媒体(7)—— 在浏览器中实现rtmp推流
示例:https://young-cowboy.github.io/gallery/rtmp_client/index.html 在国内的直播场景中通常使用,rtmp协议作为推流协议.RTMP是Rea ...
- Python TCP通信网络编程
最近在看廖雪峰老师的基础教程(http://www.liaoxuefeng.com/),今天实现了一下简单Python的Socket的网络编程. 1. Socket网络编程 Socket是网络编程的一 ...
- 不要试图用msvc来编译ffmpeg
出于学习目的,想建一个vs2010工程来编译ffmpeg(http://www.ffmpeg.org/),但是由于意义不大,并且工作量太大放弃了.原因如下: 1.一些unix平台相关的头文件.库的依赖 ...