分别考虑 c c c 的正负性:
- 当 c c c 为正数,我们肯定是想把最大子段和乘上 c c c,可以让总和最大。
证明:
设最大子段和为 m a x n maxn maxn,数组总和为 s u m sum sum,目前答案为 $ sum-maxn+maxn\times c=sum+maxn\times(c-1)$。
假设再加入一个数 p p p 更优,则答案为 s u m − m a x n − p + ( m a x n + p ) × c = s u m + ( m a x n + p ) × ( c − 1 ) sum-maxn-p+(maxn+p)\times c=sum+(maxn+p)\times (c-1) sum−maxn−p+(maxn+p)×c=sum+(maxn+p)×(c−1)。
因为我们假设加入 p p p 更优,所以
s u m + m a x n × ( c − 1 ) < s u m + ( m a x n + p ) × ( c − 1 ) sum+maxn\times(c-1)<sum+(maxn+p)\times (c-1) sum+maxn×(c−1)<sum+(maxn+p)×(c−1)
化简后,得 m a x n < m a x n + p maxn<maxn+p maxn<maxn+p,但是 m a x n maxn maxn 是最大子段和,与结论相悖。
所以把最大子段和乘上 c c c 最优。
- 当 c c c 为负数,我们肯定是想把最小子段和乘上 c c c,可以让总和最大,证明方法如上。
至此,我们可以开始编码代码了,求解最大 / / / 最小字段和类比最大字段和,但是还要注意两个细节:
- 可能不进行操作更优;
- 记得开 l o n g l o n g long long longlong。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 300010
int maxn=-1e16,ans,suma,sumb,minn=1e16,c,sum;
signed main(){
int n;
cin>>n>>c;
for(int i=1,x;i<=n;i++){
cin>>x,suma=max(suma+x,x),sumb=min(sumb+x,x),sum+=x;
maxn=max(maxn,suma),minn=min(minn,sumb);
}
cout<<max(sum,max(maxn*c+sum-maxn,minn*c+sum-minn));
return 0;
}
完结撒花(作者的第一篇题解)。