【CF573E】Bear and Bowling

题面

洛谷

题解

首先有一个贪心的结论:

我们一次加入每个数,对于\(\forall i\),位置\(i\)的贡献为\(V_i = k_i\times a_i+b_i\),其中\(k_i\)为位置\(i\)之前被选的数的个数,\(b_i\)为\(i\)之后被选的数的和。

那么我们每次选这个贡献最大的位置一定最优。

然后来证一下这个结论的正确性(直接蒯了\(\text {I} \color{#FF0000} {\text {tst}}\)的):

引理:在上述贪心策略下,如果\(a_i>a_j\)且\(i<j\),则选\(i\)之前不可能选\(j\)。

证明考虑归纳:\(i,j\)中间不存在被选中的元素时是平凡的,如果\(i,j\)中间存在p个选中的元素,若\(V_i<V_j\)则一定在\([i,j]\)之间存在至少一个\(x\)满足\(a_x<a_j\),此时没有选\(i\)所以不可能选择\(x\),与假设不符,QED。

接下来假设贪心策略不正确,即在选择了集合\(A\)之后将下标为\(x\)的位置选中,但是最优的答案是选择集合\(A+B\),其中\(x\notin B\)。那么考虑:

1、如果\(B\)中存在位置在\(x\)左边,考虑在\(x\)左边的最右位置\(y\),那么此时有\(a_y\leq a_x,V_x≥V_y\)。此时加入集合\(B\)中的其他元素考虑\(V_x,V_y\)的变化,那么在\(x\)右边的元素对\(V_x,V_y\)的贡献一样,在\(y\)左边的元素对\(V_x,V_y\)的贡献是\(a_x,a_y\),而\(x,y\)中间没有在\(B\)中的元素,所以可以发现在其他元素加入之后\(V_x\geq V_y\),所以将\(B\)中\(y\)换成\(x\)结果不劣。

2、如果\(B\)中只有在\(x\)右边的元素,考虑在\(x\)右边的最左位置\(y\),那么\(B\)集合其他的元素对\(V_x,V_y\)的贡献是一样的,所以把\(y\)换成\(x\)也不会更劣。

故上述假设不成立,贪心正确性证毕。

考虑分块维护这个最大值。

每次选完最大值,就相当于对于选定的\(pos\),\(pos\)前的位置\(i\)中\(b_i\)均加上\(a_{pos}\),\(pos\)后的位置\(i\)中\(k_i\)均加上一。因为对于同一块我们加上的\(k,b\)是一样的,而\(pos\)所在的块可以\(\sqrt n\)暴力重构,所以我们分块维护凸壳就可以了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std; const int MAX_N = 1e5 + 5;
const int LEN = 320;
int N, a[MAX_N], id[MAX_N], bel[MAX_N], L[LEN], R[LEN];
long long tk[LEN], tb[LEN], f[MAX_N], ans;
double slope(int i, int j) {
if (a[i] == a[j]) return f[i] > f[j] ? -1e20 : 1e20;
else return (double)(f[i] - f[j]) / (a[i] - a[j]);
}
long long calc(int i) { return f[i] + tk[bel[i]] * a[i] + tb[bel[i]]; }
struct Hull {
deque<int> q;
void clear() { q.clear(); }
void insert(int i) {
while (q.size() > 1 && slope(q[q.size() - 2], q[q.size() - 1])
< slope(q[q.size() - 1], i)) q.pop_back();
q.push_back(i);
}
pair<long long, int> query() {
while (q.size() > 1 && calc(q[0]) <= calc(q[1]))
q.pop_front();
return make_pair(calc(q[0]), q[0]);
}
} S[LEN];
void modify(int l, int ed, int k, int b) {
while (l <= ed) {
int x = bel[l], r = min(R[x], ed);
if (l == L[x] && r == R[x]) tk[x] += k, tb[x] += b;
else for (int i = l; i <= r; i++) f[i] += 1ll * k * a[i] + b;
l = r + 1;
}
}
pair<long long, int> query(int l, int ed) {
pair<long long, int> res = make_pair(0, 0);
while (l <= ed) {
int x = bel[l], r = min(R[x], ed);
if (l == L[x] && r == R[x]) res = max(res, S[x].query());
else for (int i = l; i <= r; i++) res = max(res, make_pair(calc(i), i));
l = r + 1;
}
return res;
}
void build(int x) {
for (int i = L[x]; i <= R[x]; i++) f[i] += tk[x] * a[i] + tb[x];
tk[x] = tb[x] = 0, S[x].clear();
for (int i = L[x]; i <= R[x]; i++) S[x].insert(id[i]);
}
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
scanf("%d", a + i);
f[i] = a[i], id[i] = i;
bel[i] = (i - 1) / LEN + 1;
if (!L[bel[i]]) L[bel[i]] = i;
R[bel[i]] = i;
}
for (int i = 1; i <= bel[N]; i++)
sort(&id[L[i]], &id[R[i] + 1], [](int l, int r) { return a[l] < a[r]; }), build(i);
long long ans = 0;
while (1) {
pair<long long, int> res = query(1, N);
if (res.first <= 0) break;
ans += res.first;
f[res.second] = -1ll << 60;
if (res.second > 1) modify(1, res.second - 1, 0, a[res.second]);
if (res.second < N) modify(res.second + 1, N, 1, 0);
build(bel[res.second]);
}
printf("%lld\n", ans);
return 0;
}

【CF573E】Bear and Bowling的更多相关文章

  1. 【CF573D】Bear and Cavalry 线段树

    [CF573D]Bear and Cavalry 题意:有n个人和n匹马,第i个人对应第i匹马.第i个人能力值ai,第i匹马能力值bi,第i个人骑第j匹马的总能力值为ai*bj,整个军队的总能力值为$ ...

  2. 【CF679D】Bear and Chase 最短路+乱搞

    [CF679D]Bear and Chase 题意:近日,鼠国的头号通缉犯,神出鬼没的怪盗——Joker正于摩登市出没!对于名侦探Jack来说,这正是将其捉拿归案的大号时机.形式化地,摩登市可以看成一 ...

  3. 【codeforces】Bear and Three Balls(排序,去重)

    Bear and Three Balls Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I6 ...

  4. 【CF771A】Bear and Friendship Condition

    题目大意:给定一张无向图,要求如果 A 与 B 之间有边,B 与 C 之间有边,那么 A 与 C 之间也需要有边.问这张图是否满足要求. 题解:根据以上性质,即:A 与 B 有关系,B 与 C 有关系 ...

  5. 【CodeForces】790 C. Bear and Company 动态规划

    [题目]C. Bear and Company [题意]给定大写字母字符串,交换相邻字符代价为1,求最小代价使得字符串不含"VK"子串.n<=75. [算法]动态规划 [题解 ...

  6. 【CodeForces】679 A. Bear and Prime 100

    [题目]A. Bear and Prime 100 [题意]有一数字x,每次可询问一个数字y是否x的因子,最后输出数字x是否素数,要求询问次数<=20. [题解]容易发现[2,100]范围内的非 ...

  7. 【CodeForces】679 B. Bear and Tower of Cubes

    [题目]B. Bear and Tower of Cubes [题意]有若干积木体积为1^3,2^3,...k^3,对于一个总体积X要求每次贪心地取<=X的最大积木拼上去(每个只能取一次)最后总 ...

  8. 【32.89%】【codeforces 574D】Bear and Blocks

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  9. 【19.05%】【codeforces 680D】Bear and Tower of Cubes

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

随机推荐

  1. Ansible17:Playbook之tags

    目录 简介 为task打tag 使用tag 执行指定tag的task 排除指定tag的task 查看playbook中的所有tag 打tag的几种方式 ansible内置tag 简介 在大型项目当中, ...

  2. Redis学习之对象系统源码分析

    背景知识: Redis并没有直接使用sds,双端链表,字典,压缩列表,跳表等这些数据结构来直接实现键值对数据库,而是基于这些对象创建了一个对象系统,这个对象系统包含5个对象:字符串对象,列表对象,哈希 ...

  3. RabbitMQ实例C#

    驱动组件.NET版本 官网推荐驱动:RabbitMQ.Client https://www.rabbitmq.com/devtools.html#dotnet-dev Connection和Chann ...

  4. javascript的对象与字符串相互转换

    因为对象不利于网络传输,因此要转换成字符串,转换成字符串之后又要考虑怎么将这个字符串转换回对象,以便取得对象中的属性. 常用的做法是将对象转换为JSON字符串,这里的转换方法也是用的JSON官方提供的 ...

  5. [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'information_schema.PROFILING.SEQ'

    在Navicat Premium中执行Mysql的一条删除语句,虽然执行成功了,却提示已下错误: 受影响的行: 时间: .005s of ORDER BY clause is not in GROUP ...

  6. LoadRunner 11 的兼容问题及权限问题

    1.LoadRunner 11 在服务器系统中可能出现 不兼容问题. 要对 安装目录bin\LRLauncherApp.exe 和 bin\wlrun.exe 右键属性兼容性(视系统定). 2.如果填 ...

  7. 2019 上海轻轻java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.上海轻轻等公司offer,岗位是Java后端开发,因为发展原因最终选择去了上海轻轻,入职一年时间了,也成为了面 ...

  8. PHP错误日志相关

    https://cloud.tencent.com/developer/article/1167951   php错误日志总结 https://cloud.tencent.com/developer/ ...

  9. 隐马尔科夫模型(Hidden Markov Models) 系列之四

    转自:http://blog.csdn.net/eaglex/article/details/6430389 前向算法(Forward Algorithm) 一.如果计算一个可观察序列的概率?   1 ...

  10. nginx rewrite模块

    return 从0.8.42版本开始, return 语句可以指定重定向 url (状态码可以为如下几种 301,302,303,307), 也可以为其他状态码指定响应的文本内容,并且重定向的url和 ...