@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 个位置,则新序列权值为:

\[c'=c-a[i]*i+a[i]*j+(s[j]-s[i])
\]

你看,它多么的斜率优化。

求最大值是上凸包,横坐标为 \(-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的更多相关文章

  1. Codeforces 631E Product Sum 斜率优化

    我们先把问题分成两部分, 一部分是把元素往前移, 另一部分是把元素往后移.对于一个 i 后的一个位置, 我们考虑前面哪个移到这里来最优. 我们设最优值为val,   val = max(a[ j ] ...

  2. 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 ...

  3. 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 ...

  4. Codeforces 396B On Sum of Fractions 数论

    题目链接:Codeforces 396B On Sum of Fractions 题解来自:http://blog.csdn.net/keshuai19940722/article/details/2 ...

  5. [codeforces631E]Product Sum

    E. Product Sum time limit per test: 1 second memory limit per test: 256 megabytes input:standard inp ...

  6. codeforces 963A Alternating Sum

    codeforces 963A Alternating Sum 题解 计算前 \(k\) 项的和,每 \(k\) 项的和是一个长度为 \((n+1)/k\) ,公比为 \((a^{-1}b)^k\) ...

  7. codeforces 1217E E. Sum Queries? (线段树

    codeforces 1217E E. Sum Queries? (线段树 传送门:https://codeforces.com/contest/1217/problem/E 题意: n个数,m次询问 ...

  8. Codeforces 577B Modulo Sum

    http://codeforces.com/problemset/problem/577/B 题意:有n个数,求有无一个子序列满足和是m的倍数 思路:用模下的背包做,发现n是十的六次方级别,但是有个神 ...

  9. Codeforces 85 D. Sum of Medians

    题目链接:http://codeforces.com/contest/85/problem/D 做法果然男默女泪啊..... 大概就是直接开了一个$vector$每次插入删除都用自带的$insert$ ...

随机推荐

  1. 【洛谷P2722 USACO】 总分 01背包模板

    P2722 总分 Score Inflation 题目背景 学生在我们USACO的竞赛中的得分越多我们越高兴. 我们试着设计我们的竞赛以便人们能尽可能的多得分,这需要你的帮助 题目描述 我们可以从几个 ...

  2. gb2312的6763个汉字

    0a啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥薄雹保堡 ...

  3. Can you find it? HDU-2141 (二分查找模版题)

    Description Give you three sequences of numbers A, B, C, then we give you a number X. Now you need t ...

  4. Spring Boot 数据库连接池参数

    挑战A.I.,赢百万奖金......了解更多详情>>> Tomcat JDBC 连接池 Spring Boot 默认选择 Tomcat JDBC Pool 作为数据库连接池.Tomc ...

  5. 关于PHP学习--摘自知乎

    主要是学框架(其实也没啥可学的).数据库.服务器.linux. 所以我推荐apache/nginx文档,框架的文档,mysql的文档,linux使用说明,等等等等. PHP: PHP 手册MySQL ...

  6. 第三方数据库管理工具Navicat使用教程

    一.Navicat Premium是一个功能强大的第三方数据库管理工具,可以连接管理MySQL.Oracle.PostgreSQL.SQLite 及 SQL Server数据库. 使用Navicat软 ...

  7. text-align:justify在项目中碰到的问题

    最近在项目中,使用了一个新的样式属性:text-align:justigy,这个属性在使用过程中遇到了一些小异常,现在总结下.  text-align有一个属性值为justify,为对齐之意.其实现的 ...

  8. 自学FPGA笔记之 “sublime的使用”

    之前用的notepad++,现在新发现一款软件:sublime.调出一整个逻辑块,写代码能快一点,而且常见的always之类的词汇还不易输入错误,并且比较不容易漏掉begin  end.现在总结一下自 ...

  9. 【JZOJ4756】【NOIP2016提高A组模拟9.4】幻象

    题目描述 phantom是一位爱思考的哲♂学家. 最近phantom得到了森の妖精的真传.在他练功的时候, 每秒他的思绪中都有一定的概率浮现出奇♂异的幻象,持续x秒的幻象将产生x^2 的幻象值. ph ...

  10. PyCharm2019 永久激活

    <!-- 2019激活码 2019-06-21新更新 --> D00F1BDTGF-eyJsaWNlbnNlSWQiOiJEMDBGMUJEVEdGIiwibGljZW5zZWVOYW1l ...