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,'
',true);
return 0;
}
Summary
遇到最大化一个值的题目,可以通过数学推导变成单变量极值问题,然后DP或者数学求解。