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 gather at the bar to talk about intriguing problems about maximising some values. This time the problem is really special.

You are given an array a of length n. The characteristic of this array is the value  — the sum of the products of the valuesai by i. One may perform the following operation exactly once: pick some element of the array and move to any position. In particular, it‘s allowed to move the element to the beginning or to the end of the array. Also, it‘s allowed to put it back to the initial position. The goal is to get the array with the maximum possible value of characteristic.

Input

The first line of the input contains a single integer n (2 ≤ n ≤ 200 000) — the size of the array a.

The second line contains n integers ai (1 ≤ i ≤ n, |ai| ≤ 1 000 000) — the elements of the array a.

Output

Print a single integer — the maximum possible value of characteristic of a that can be obtained by performing no more than one move.

Examples

input

44 3 2 5

output

39

Note

In the first sample, one may pick the first element and place it before the third (before 5). Thus, the answer will be3·1 + 2·2 + 4·3 + 5·4 = 39.

In the second sample, one may pick the fifth element of the array and place it before the third. The answer will be1·1 + 1·2 + 1·3 + 2·4 + 7·5 = 49.

题意:

  给你一个序列a,让你求∑ a[i]*i 是多少

  你可以进行一次操作:将任意位置的一个数组元素拿出来再插入任意一个新的位置或者不进行此操作。

  问你最大的∑ a[i]*i 是多少。

题解:

  首先假设拿出元素向前面的位置插入

  那么 dp[i] = max(pre[i-1]+i*a[i],pre[i-1]+sum[i-1]-sum[j-1] +j*a[i]);

  pre表示前缀答案和,sum表示数组前缀和,这个转移方程是可以用斜率优化的,只不过斜率并不满足单调性质,那么我们就要手动维护一个凸包来二分找答案了。。。

  拿元素向后插是一样的道理

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 2e5+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10;

LL dp1[N],dp2[N],sum[N],las[N],pre[N];
LL splopex(int i,int j) {
    return sum[i-1] - sum[j-1];
}
LL splopey(int i,int j) {
    return i - j;
}
int n,a[N],q[N];
int main() {
        scanf("%d",&n);
        for(int i = 1; i <= n; ++i) scanf("%d",&a[i]);
        for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] + a[i];
        int head = 1 , tail = 1;
        las[0] = 0;
        for(int i = 1; i <= n; ++i) {
            dp1[i] = las[i-1] + 1LL * i * a[i];
            las[i] = dp1[i];
            if(head == tail) {q[tail++] = i;continue;}
            int l = head, r = tail-1,md;
            while( l < r ) {
                md =  (l+r)>>1;
                if(md + 1 < tail && splopex(q[md+1],q[md]) < 1LL*splopey(q[md+1],q[md])*a[i])
                    l = md + 1;
                else
                    r = md;
            }
            md = r;
            dp1[i] = max(las[i-1] + 1LL * sum[i-1] - 1LL * sum[q[md]-1] + 1LL*q[md]*(a[i]),dp1[i]);
            while(head + 1<tail && splopey(i,q[tail-1])*splopex(q[tail-1],q[tail-2])
                                >= splopey(q[tail-1],q[tail-2])*splopex(i,q[tail-1])) tail--;
            q[tail++] = i;
        }

        pre[n+1] = 0;
        head = 1, tail = 1;
        for(int i = n; i >= 1; --i) {
            dp2[i] = pre[i+1] + 1LL * i * a[i];
            pre[i] = dp2[i];
            if(head == tail) {q[tail++] = i;continue;}
            int l = head, r = tail-1,md;
            while( l < r ) {
                md =  (l+r)>>1;
                if(md + 1 < tail && splopex(q[md+1]+1,q[md]+1) < 1LL*splopey(q[md+1],q[md])*a[i])
                    l = md + 1;
                else
                    r = md;
            }
            md = r;
            dp2[i] = max(pre[i+1] - 1LL * sum[q[md]] + 1LL * sum[i] + 1LL*q[md]*(a[i]),dp2[i]);
            while(head + 1<tail && splopey(i,q[tail-1])*splopex(q[tail-1]+1,q[tail-2]+1)
                                <= splopey(q[tail-1],q[tail-2])*splopex(i+1,q[tail-1]+1)) tail--;
            q[tail++] = i;
        }
        LL ans = -INF;
        for(int i = 1; i <= n; ++i) {
            ans = max(ans, max(dp1[i]+pre[i+1],dp2[i]+las[i-1]));
        }
        cout<<ans<<endl;
    return 0;
}
时间: 2024-10-13 11:14:28

Codeforces Round #344 (Div. 2) E. Product Sum 二分斜率优化DP的相关文章

Codeforces Round #262 (Div. 2) 460C. Present(二分)

题目链接:http://codeforces.com/problemset/problem/460/C C. Present time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Little beaver is a beginner programmer, so informatics is his favorite subjec

Codeforces Round #556 (Div. 2) - C. Prefix Sum Primes(思维)

Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 1000 mSec Problem Description Input Output Sample Input 51 2 1 2 1 Sample Output 1 1 1 2 2 题解:这个题有做慢了,这种题做慢了和没做出来区别不大... 读题的时候脑子里还意识到素数除了2都是奇数,读完之后就脑子里就只剩欧拉筛了,贪心地构造使得前缀和是连续的素数,那

Codeforces Round #426 (Div. 2) D. The Bakery(线段树维护dp)

题目链接: Codeforces Round #426 (Div. 2) D. The Bakery 题意: 给你n个数,划分为k段,每段的价值为这一段不同的数的个数,问如何划分,使得价值最大. 题解: 考虑dp[i][j]表示划分为前j个数划分为i段的最大价值,那么这就是一个n*n*k的dp, 考虑转移方程dp[i][j]=max{dp[i][k]+val[k+1][j]},我们用线段树去维护这个max,线段树上每个节点维护的值是dp[i][k]+val[k+1][j],对于每加进来的一个数a

Codeforces Round #459 (Div. 2) C 思维,贪心 D 记忆化dp

Codeforces Round #459 (Div. 2) C. The Monster 题意:定义正确的括号串,是能够全部匹配的左右括号串. 给出一个字符串,有 (.). ? 三种字符, ? 可以当作 ( 可 ) . 问这个字符串有多少个子串是正确的括号串. tags:好考思维,想不到.. 预处理出每个字符向左向右最多可以匹配到哪里,再 O(n*n) 枚举所有区间,看是否符合条件. // C #include<bits/stdc++.h> using namespace std; #pra

Codeforces Round #470 (Div 2) B 数学 C 二分+树状数组 D 字典树

Codeforces Round #470 B. Primal Sport 数学题,对 x2 和 x1 分解质因子即可. #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b;

Codeforces Round #274 (Div. 2) E. Riding in a Lift(DP)

Imagine that you are in a building that has exactly n floors. You can move between the floors in a lift. Let's number the floors from bottom to top with integers from 1 to n. Now you're on the floor number a. You are very bored, so you want to take t

Codeforces Round #319 (Div. 2) B Modulo Sum

直接O(n*m)的dp也可以直接跑过. 因为上最多跑到m就终止了,因为sum[i]取余数,i = 0,1,2,3...,m,会有m+1种可能,m的余数只有m种必然有两个相同. #include<bits/stdc++.h> using namespace std; const int maxn = 1e3+5; int cnt[maxn]; bool dp[maxn][maxn]; #define Y { puts("YES"); return 0; } int main(

Codeforces Round #344 (Div. 2)(按位或运算)

Blake is a CEO of a large company called "Blake Technologies". He loves his company very much and he thinks that his company should be the best. That is why every candidate needs to pass through the interview that consists of the following probl

Codeforces Round #575 (Div. 3) B. Odd Sum Segments (构造,数学)

B. Odd Sum Segments time limit per test3 seconds memory limit per test256 megabytes inputstandard input outputstandard output You are given an array a consisting of n integers a1,a2,-,an. You want to split it into exactly k non-empty non-intersecting