【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. EasyNetQ笔记

    Each call to Subscribe creates a new queue consumer. If you call Subscribe two times with the same m ...

  2. [转帖]ZEROCONF是什么

    ZEROCONF是什么 xjsunjie关注0人评论9867人阅读2014-05-13 16:12:18 https://blog.51cto.com/xjsunjie/1410592 奇怪 两个文档 ...

  3. linux下c++如何输入不回显

    #include <stdio.h> #include <termios.h> #include <unistd.h> #include <iostream& ...

  4. Mono 下的 ASP.NET 可以运行在哪些 Web 服务器上?

    Mono has an implementation of ASP.NET 2.0, ASP.NET MVC and ASP.NET AJAX. Quick Resources: ASP.NET FA ...

  5. Python转义序列

    正则表达式参考:https://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html

  6. 【02】Saltstack:Grains and Pillar

    写在前面的话 上一节谈及了 Saltstack 的安装和初始化配置,本节将谈谈 Saltstack 中两个重要的东西,Grains 和 Pillar. 数据系统 Grains 入门 Grains 是静 ...

  7. spring好文章整理

    彻底搞明白Spring中的自动装配和Autowired IDEA编译spring 5源码 Spring源码——IDEA读Spring源码环境搭建 导入spring源码org.springframewo ...

  8. SQLServer之Case用法

    定义 计算条件列表,并返回多个可能的结果表达式之一. 表达式类型 case具有两种格式: 简单case表达式,它通过将表达式与一组简单的表达式进行比较来确定结果. case搜索表达式,它通过计算一组布 ...

  9. 使用<label>标签修改input[type="checkbox"]的样式

    因为<label>的特性有两点 : ①不呈现任何效果, ②用户点击该标签, 浏览器能自动将焦点转移到相关的表单控件上. <form> <input type=" ...

  10. Vue递归组件实现层层嵌套显示数据

    问题来自朋友...记录一下 需求是表格头部后端返回的数据中是不确定的 n维数据,表头存在于 listVo 字段中,如何实现层层显示呢? 温馨提示,以下内容为5张大图,请打开 WIFI 享用... 以下 ...