【IOI2020国家集训队作业 Part 1】CF573E Bear and Bowling

题目

题目描述
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; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值