@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. GIT → 10:基于IntelliJ IDEA的Git 操作

    GIT → 10:基于IntelliJ IDEA的Git 操作

  2. windows 环境下搭建docker私有仓库

    windows 环境下搭建docker私有仓库 1.在公用仓库中pull仓库镜像 docker pull regitry 2.启动仓库镜像 //-d意思是后台运行,-p是做端口映射,这里是将本地的50 ...

  3. VUE.之安装 font-awesome

    VUE.之安装 font-awesome 我们在项目中经常使用各种图标:font-awesome (http://fontawesome.dashgame.com/) 1.npm 安装font-awe ...

  4. 洛谷P1969 [NOIP2013提高组Day2T1] 积木大赛

    P1969 积木大赛 题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前, ...

  5. 【P2616】 【USACO10JAN】购买饲料II Buying Feed, II

    P2616 [USACO10JAN]购买饲料II Buying Feed, II 题目描述 Farmer John needs to travel to town to pick up K (1 &l ...

  6. Jquery选择器分类:基本选择器,层次选择器,过滤选择器,表单选择器。

    基本选择器 说明:通过元素id.class和标签名等来查找DOM元素 1.id选择器:$("#test");//选取id为test的元素 2.类选择器:$(".test& ...

  7. golang之for

    1.常规for.结构如下: for 初始化语句; 条件语句; 修饰语句{ 循环体 } 2.条件for.结构如下: 初始化语句; for 条件语句 { 循环体 } 3.死循环 for.结构如下: for ...

  8. Faster RCNN算法训练代码解析(1)

    这周看完faster-rcnn后,应该对其源码进行一个解析,以便后面的使用. 那首先直接先主函数出发py-faster-rcnn/tools/train_faster_rcnn_alt_opt.py ...

  9. web服务发展历程

    PhP发展历史1.php: 开始名字含义:personal home page 个人网页 现在名字含义:HyperText Perprocessor 超文本预处理语言 预处理: 说明PHP是在服务器预 ...

  10. 写论文,没数据?R语言抓取网页大数据

    写论文,没数据?R语言抓取网页大数据 纵观国内外,大数据的市场发展迅猛,政府的扶持也达到了空前的力度,甚至将大数据纳入发展战略.如此形势为社会各界提供了很多机遇和挑战,而我们作为卫生(医学)统计领域的 ...