@codeforces - 631E@ Product Sum
@desription@
给定一个序列 a,定义它的权值 \(c = \sum_{i=1}^{n}a_i\)。
你可以做如下的操作恰好一次:选择一个数,然后将它移动到一个位置(可以是原位置,序列开头与结尾)。
最大化序列权值。
input
第 1 行一个整数 n,表示序列长度(2 <= n <= 200000)。
第 2行 n 个整数 a1, a2, ..., an,表示这个序列(|ai| <= 1000000)。
output
输出一个整数,表示最大的序列权值。
sample input
4
4 3 2 5
sample output
39
sample explain
将 4 移动到 5 之前,得到 \(c = 1*3 + 2*2 + 3*4 + 4*5 = 39\)。

@solution@
移动可以向前移动也可以向后移动,我们仅考虑向后这一种,向前同理。
记原序列权值为 \(c\),再记 \(s[i]=\sum_{p=1}^{i}a_p\)。
考虑将第 i 号元素移动到第 j 个位置,则新序列权值为:
\]
你看,它多么的斜率优化。
求最大值是上凸包,横坐标为 \(-j\),从后往前是单增的。
但是……斜率为 \(a[i]\),是不单调的。
所以我们必须在凸包上作二分寻找答案。
一开始我很懵逼,凸包不应该是三分求极值吗?后来我才发现,二分原来是二分斜率。凸包上斜率是单增的,所以可以使用二分。(但是三分好像也可以……只是大概没人想写而已……明明三分更容易调错来着 qwq)。
二分找什么呢?就是找到一个点,它和它前驱的斜率大于等于 \(a[i]\),它和它后继的斜率小于等于 \(a[i]\)。
注意二分常见的错误:边界。
@accepted code@
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 200000;
int n;
ll a[MAXN + 5], s1[MAXN + 5], s2[MAXN + 5];
ll c1(int i) {return s1[n] - a[i]*i + s2[i-1];}
ll c2(int i) {return s1[n] - a[i]*i + s2[i];}
ll k1(int i) {return -a[i];}
ll k2(int i) {return a[i];}
ll x1(int j) {return j;}
ll x2(int j) {return -j;}
ll y1(int j) {return -s2[j-1];}
ll y2(int j) {return -s2[j];}
int stk[MAXN + 5], tp;
double slope1(int p, int q) {return 1.0*(y1(p) - y1(q))/(x1(p) - x1(q));}
double slope2(int p, int q) {return 1.0*(y2(p) - y2(q))/(x2(p) - x2(q));}
int main() {
scanf("%d", &n);
for(int i=1;i<=n;i++)
scanf("%lld", &a[i]);
for(int i=1;i<=n;i++) {
s1[i] = s1[i-1] + a[i]*i;
s2[i] = s2[i-1] + a[i];
}
ll ans = -(1LL<<62); tp = 0;
for(int i=1;i<=n;i++) {
while( tp > 1 && slope1(stk[tp - 1], stk[tp]) <= slope1(stk[tp], i) )
tp--;
stk[++tp] = i;
int le = 1, ri = tp;
while( le < ri ) {
int mid = (le + ri) >> 1;
if( slope1(stk[mid], stk[mid+1]) <= k1(i) ) ri = mid;
else le = mid + 1;
}
ans = max(ans, c1(i) + y1(stk[le]) - k1(i)*x1(stk[le]));
}
tp = 0;
for(int i=n;i>=1;i--) {
while( tp > 1 && slope2(stk[tp - 1], stk[tp]) <= slope2(stk[tp], i) )
tp--;
stk[++tp] = i;
int le = 1, ri = tp;
while( le < ri ) {
int mid = (le + ri) >> 1;
if( slope2(stk[mid], stk[mid+1]) <= k2(i) ) ri = mid;
else le = mid + 1;
}
ans = max(ans, c2(i) + y2(stk[le]) - k2(i)*x2(stk[le]));
}
printf("%lld\n", ans);
}
@details@
一开始我从前往后和从后往前都用同一个横坐标,然后因为枚举顺序不一样,导致一个是单增的一个是单减的。
单增的还好,单减的那个让我二分时各种边界错误……调到死都调不出来……
最后索性把单减那个横坐标取个相反数,变成单增的。然后一遍过 =_=。
@codeforces - 631E@ Product Sum的更多相关文章
- Codeforces 631E Product Sum 斜率优化
我们先把问题分成两部分, 一部分是把元素往前移, 另一部分是把元素往后移.对于一个 i 后的一个位置, 我们考虑前面哪个移到这里来最优. 我们设最优值为val, val = max(a[ j ] ...
- Codeforces Round #344 (Div. 2) E. Product Sum 维护凸壳
E. Product Sum 题目连接: http://www.codeforces.com/contest/631/problem/E Description Blake is the boss o ...
- Codeforces Round #344 (Div. 2) E. Product Sum 二分斜率优化DP
E. Product Sum Blake is the boss of Kris, however, this doesn't spoil their friendship. They often ...
- Codeforces 396B On Sum of Fractions 数论
题目链接:Codeforces 396B On Sum of Fractions 题解来自:http://blog.csdn.net/keshuai19940722/article/details/2 ...
- [codeforces631E]Product Sum
E. Product Sum time limit per test: 1 second memory limit per test: 256 megabytes input:standard inp ...
- codeforces 963A Alternating Sum
codeforces 963A Alternating Sum 题解 计算前 \(k\) 项的和,每 \(k\) 项的和是一个长度为 \((n+1)/k\) ,公比为 \((a^{-1}b)^k\) ...
- codeforces 1217E E. Sum Queries? (线段树
codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...
- Codeforces 577B Modulo Sum
http://codeforces.com/problemset/problem/577/B 题意:有n个数,求有无一个子序列满足和是m的倍数 思路:用模下的背包做,发现n是十的六次方级别,但是有个神 ...
- Codeforces 85 D. Sum of Medians
题目链接:http://codeforces.com/contest/85/problem/D 做法果然男默女泪啊..... 大概就是直接开了一个$vector$每次插入删除都用自带的$insert$ ...
随机推荐
- python基础(输出、变量、常量、数据类型、流程控制)
输出 print print("Hello World!") # python2 和 python3 的区别 # python2 # coding:utf-8 print 123 ...
- spring基于xml的声明式事务控制配置步骤
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- VC开发多语言界面 多种方法(非常easy) 有源代码
源代码地址(专业定制程序:MCU,Windows,Android .VC串口,Android蓝牙等不限.) (需源代码先留邮箱)先上图 1.通过遍历 得到全部控件ID号与TEXT,得到一个中文语言配置 ...
- Ubuntu小知识:更改主机名
Linux主机名是在安装Linux操作系统的过程中设定的,并作为网络中的某一台主机的唯一标志,但是在安装好Linux系统后,如果想修改主机名,该怎么办呢?本文介绍基于Ubuntu Desktop 9. ...
- go struct 工厂
- 开源PaaS平台:Cloudify
Cloudify是gigaspaces公司推出的基于java的paas平台. refer to :http://timeson.iteye.com/blog/1699730
- [运维]ESXI Web Client 标签: vmware运维服务器 2017-05-28 20:59 597人阅读 评论(9)
ESXI安装完成之后,配置好ip,我们就可以使用了?那么如何使用呢?一般来说有两种方式,一种是安装专门的管理客户端,client端,另一种更加方便,就是使用web client端. 下面来介绍一下es ...
- Redis 源码学习之 Redis 事务Nosql
Redis事务提供了一种将多个命令请求打包,然后一次性.按照顺序地执行多个命令的机制,并且在事务执行的期间,服务器不会中断事务而去执行其他不在事务中的命令请求,它会把事务中所有的命令都执行完毕才会去执 ...
- 用JS实线放大镜的效果
今天花了点时间,复习了下使用原生JS实线放大镜的效果.在制作过程中,也是很到了一些问题,在这里总结下. HTML代码如下: <div id="preview"> < ...
- Find Minimumd in Rotated Sorted Array
二分搜索查最小数,from mid to分别为区间的第一个,中位数,和最后一个数 if(from<=mid&&mid<=to)//顺序,第一个即为最小值 return fr ...