题意:
给你一个序列,你可以选择它的前缀和后缀中的每个数字都乘以-1。前缀和后缀可以交叉也可以为空。
问能得到的最大序列和是多少。
算法:
1、如果前缀和后缀交叉,那么交叉的部分还是保持原状。
(s1 [s2 )s3 ] is equal to (s1)s2[s3] (s1,s2,s3 - some subsequences).
2、令S = A1+A2+...+A3,那么当改变这一段每个数字的符号时,S变为-S。
3、那么假设我们选择一段前缀和后缀后剩余不变的中间部分的序列和为S1,总序列的和为S。
那么操作进行后的序列和为 -(S-S1)+S1 = 2*S1-S.
S是固定的,那么只要S1尽可能大。那么问题就转化为求序列的最大子序列和。
4、求序列的最大子序列
mx = 0;
for(i=0;i<n;++i)
{
sum += a[i];
if(sum < 0)
sum = 0;
mx = max(mx, sum);
}
P.S还是要学会问题的转化啊。。。
#include<cstdio>
using namespace std;
typedef long long ll;
ll a[100010];
ll max(ll x,ll y)
{
return x>y?x:y;
}
int main()
{
int n;
ll s;
while(scanf("%d",&n)!=EOF)
{
s = 0;
for(int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
s+=a[i];
}
ll mx = 0LL,sum = 0LL;
for(int i=1;i<=n;i++)
{
sum+=a[i];
mx = max(mx,sum);
if(sum<0)
sum = 0;
}
printf("%I64d\n",2*mx-s);
}
return 0;
}