1. 程式人生 > >【極值問題】【CF33C】 Wonderful Randomized Sum

【極值問題】【CF33C】 Wonderful Randomized Sum

傳送門

Description

給你一個數列\(A\),你可以選擇任意一個字首和任意一個字尾,字首字尾可重合。給他們乘\(-1\)。求最大能獲得的序列和。

Input

第一行是一個數\(n\)代表數列長度

第二行\(n\)個數字,代表序列的元素

Output

一個數字代表答案

Hint

\(1~\leq~n~\leq~10^5\)

Solution

發現重合的部分相當於沒有修改。於是不妨設前後綴沒有重合。

設修改的原序列字首和為\(A\),字尾和為\(B\),未修改的部分為\(C\),序列和為\(S\),則有\(A+B+C=S\)

題目要求最大化\(-(A+B)+C\)

。又因為\(A+B=S-C\)

於是要最大化\(2C-S\)。發現\(S\)是一個不變數,於是要最大化\(C\)。即求一個最大欄位和。顯然可以DP求解。於是本題可以解決了。

Code

#include<cstdio>
#define rg register
#define ci const int
#define cl const long long

typedef long long int ll;

template <typename T>
inline void qr(T &x) {
    rg char ch=getchar(),lst=' ';
    while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
    while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    if(lst == '-') x=-x;
}

namespace IO {
    char buf[120];
}

template <typename T>
inline void qw(T x,const char aft,const bool pt) {
    if(x < 0) {x=-x,putchar('-');}
    rg int top=0;
    do {IO::buf[++top]=x%10+'0';} while(x/=10);
    while(top) putchar(IO::buf[top--]);
    if(pt) putchar(aft);
}

template <typename T>
inline T mmax(const T a,const T b) {return a > b ? a : b;}
template <typename T>
inline T mmin(const T a,const T b) {return a < b ? a : b;}
template <typename T>
inline T mabs(const T a) {return a < 0 ? -a : a;}

template <typename T>
inline void mswap(T &_a,T &_b) {
    T _temp=_a;_a=_b;_b=_temp;
}

const int maxn = 100010;

int n,ans,sum;
int MU[maxn],frog[maxn];

int main() {
    qr(n);
    for(rg int i=1;i<=n;++i) qr(MU[i]);
    for(rg int i=1;i<=n;++i) {
        frog[i]=mmax(frog[i],frog[i-1]+MU[i]);
        ans=mmax(ans,frog[i]);
        sum+=MU[i];
    }
    qw((ans<<1)-sum,'\n',true);
    return 0;
}

Summary

遇到最大化一個值的題目,可以通過數學推導變成單變數極值問題,然後DP或者數學求解。