bzoj3024(斜率优化+二分)

Description

给定N个数A[1..n]。有两种操作:
操作1:对于某对(i,j)(i

Input

第一行一个数N,N<=300000
接下来N个数表示A[1..n]

Output

两个数,分别表示只使用一次操作1和只使用一次操作2的两种情况下,sum(A[1..n])的和的最大值。

Sample Input

6

6 10 -7 2 5 -12

Sample Output

19

56

解释:

操作1取i=3,j=5;

操作2取i=2,j=6

HINT

Source


其实这道题是不难的….
写出状态转移方程,瞎瘠薄移一下就好了:
s i s k i k > a j
在上凸包上二分查找就行了
然鹅一开始没看到 i < j ,也就是必须得有更改
而且在二分的时候也出了问题
最后要判断右端点左端点,有三个可能的 r e t u r n 的值
还是写太急了啊…..

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n , a[301000] ;
ll s[301000] ,dp[301000];
ll q[301000] , head , tail;
bool flag;
ll read(){
    ll sum = 0;char c = getchar();bool flag = true;
    while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
    while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
    if(flag)  return sum;
     else return -sum;
}  
double f(ll k , ll i){ 
    return (s[i] - s[k] ) * 1.0 /(i - k) ;
}
int find(int x){
    ll l = head + 1 , r = tail;
    while( l + 1 < r ){
        int mid = (l + r) >> 1;
        if( f(q[mid] , q[mid - 1]) > x) l = mid;
            else r = mid;
    } 
    if( f(q[r] , q[r - 1]) > x ) return r;
        else if(f(q[l],q[l - 1]) > x ) return l;
            else return l - 1;
}
void work(){
    q[1] = 0;head = 1;tail = 1;
    ll ans = -100000000000000000LL;
    for(int i = 2;i <= n;++i){
        while(tail - head > 1 && f(q[tail - 1], q[tail]) > f(q[tail - 2],q[tail - 1])) q[--tail] = q[tail + 1];
        int k = q[find(a[i])];
        dp[i] = s[k] - a[i] * k  + a[i] * i - s[i];
        ans = max ( ans , dp[i] );
        q[++tail] = i - 1;
    }
    printf("%lld\n",ans + s[n]);


    q[1] = 0;head = 1;tail = 1;
    for(int i = 1;i <= n;++i) s[i] = a[n - i + 1];
    for(int i = 1;i <= n;++i) a[i] = s[i];
    memset(s,0,sizeof(s));
    for(int i = 1;i <= n;++i)
     s[i] = s[i - 1] + a[i];
    ans = -100000000000000000LL;
    for(int i = 2;i <= n;++i){
        while(tail - head > 1 && f(q[tail - 1], q[tail]) > f(q[tail - 2],q[tail - 1])) q[--tail] = q[tail + 1];
        int k = q[find(a[i])];
        dp[i] = s[k] - a[i] * k  + a[i] * i - s[i];
        ans = max ( ans , dp[i] );
        q[++tail] = i - 1;
    }
    printf("%lld\n",ans+s[n]);
    return;
}
int main(){
    n = read();
    for(int i = 1;i <= n;++i) a[i] = read();
    for(int i = 1;i <= n;++i) s[i] = s[i - 1] + a[i];

    work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/81021543