zoukankan      html  css  js  c++  java
  • 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
    4
    4 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;
    }
  • 相关阅读:
    这鸡汤、真香
    linux 编译安装python并且安装虚拟环境工具
    前端数据删除
    前后端分离DRF项目初始化
    ubuntu 安装nginx docker
    ubuntu安装vue
    虚拟环境安装
    sql语句优化
    Python之网络编程 进程 线程 协程
    Python之网络编程 文件上传 基于udp的协议的socket socketsever同时接收多方消息
  • 原文地址:https://www.cnblogs.com/zxhl/p/6415658.html
Copyright © 2011-2022 走看看