题目
题目描述
Limak is an old brown bear. He often goes bowling with his friends. Today he feels really good and tries to beat his own record!
For rolling a ball one gets a score — an integer (maybe negative) number of points. Score for ii -th roll is multiplied by ii and scores are summed up. So, for kk rolls with scores s_{1},s_{2},…,s_{k}s
1
,s
2
,…,s
k
, total score is . Total score is 00 if there were no rolls.
Limak made nn rolls and got score a_{i}a
i
for ii -th of them. He wants to maximize his total score and he came up with an interesting idea. He will cancel some rolls, saying that something distracted him or there was a strong wind.
Limak is able to cancel any number of rolls, maybe even all or none of them. Total score is calculated as if there were only non-canceled rolls. Look at the sample tests for clarification. What maximum total score can Limak get?
输入格式
The first line contains single integer nn ( 1<=n<=10^{5}1<=n<=10
5
).
The second line contains nn space-separated integers a_{1},a_{2},…,a_{n}a
1
,a
2
,…,a
n
( |a_{i}|<=10^{7})∣a
i
∣<=10
7
) - scores for Limak’s rolls.
输出格式
Print the maximum possible total score after choosing rolls to cancel.
题意翻译
给定一个长度为 nn 的序列 a_{1\dots n}a
1…n
。
你要求一个 aa 的子序列 b_{1\dots m}b
1…m
(可以为空),使得 \sum_{i=1}^m ib_i∑
i=1
m
ib
i
的值最大。
n \le 10^5n≤10
5
,|a_i| \le 10^7∣a
i
∣≤10
7
。
输入输出样例
输入 #1复制
5
-2 -8 0 5 -3
输出 #1复制
13
输入 #2复制
6
-10 20 -30 40 -50 60
输出 #2复制
400
说明/提示
In first sample Limak should cancel rolls with scores -8−8 and -3−3 . Then he is left with three rolls with scores -2,0,5−2,0,5 . Total score is 1·(-2)+2·0+3·5=131⋅(−2)+2⋅0+3⋅5=13 .
In second sample Limak should cancel roll with score -50−50 . Total score is 1·(-10)+2·20+3·(-30)+4·40+5·60=4001⋅(−10)+2⋅20+3⋅(−30)+4⋅40+5⋅60=400 .
思路
考虑贪心:每次选择贡献最大的位置,直到贡献非正,此时贡献和即为答案。
那么我们只需要快速维护这个贪心,具体地说,每个位置有一个权值 b i b_i bi 和一个固定的值 a i a_i ai,需要支持四种操作:
前缀
b
i
b_i
bi 加相同值。
后缀
b
i
b_i
bi 加
a
i
a_i
ai。
查询
b
i
b_i
bi 的全局最大值。
删除一个位置。
一般线段树没法做,我们考虑分块。(其实这是一种经典分块类型)
每
n
\sqrt{n}
n 个元素分一块,那对于每一块就要实现:
整体加。
整体加
a
i
a_i
ai。
查询整体最大值。
重构。
可以发现大概是类似斜率优化那套式子,维护上凸壳即可。
注意到
a
i
a_i
ai 始终不变,而要求的斜率不断递减,可以用单调队列维护,重构的时候也不用重新排序了。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=500077;
vector<int>p[N];
int vis[N],ans[N][2];
void dfs(int x,int y)
{
if(vis[x]) return;
else vis[x]=y;
int sz=p[x].size();
for(int i=0; i<sz; i++) dfs(p[x][i],1^y);
}
int main()
{
int n,x,y;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d%d",&x,&y);
if(ans[x][0])
{
p[i].push_back(ans[x][0]);
p[ans[x][0]].push_back(i);
ans[x][0]=0;
}
else ans[x][0]=i;
if(ans[y][1])
{
p[i].push_back(ans[y][1]);
p[ans[y][1]].push_back(i);
ans[y][1]=0;
}
else ans[y][1]=i;
}
for(int i=1; i<=n; i++)
{
dfs(i,0);
if(vis[i]) putchar('r');
else putchar('b');
}
return 0;
}