推荐一边个人认为比较好的博客:https://blog.csdn.net/qq_37594941/article/details/82589288
题意:给出一个长度为n的数列,每个数都可以和左边的数或者右边的数结合(紧挨着的),结合后的结果为结合的数减去被结合的数得到的值,结合n-1次后,只剩下一个数,问这个数最大是多少。
Solution:只要弄明白了下面这个事实,这个题就好做了:至少有一个数没有做过被减数,并且有且只有一个数没有做过减数,也就是说,至少有一个数没有减过其他的数,并且至少有一个数没有被其他数减过,最关键的是要理解:除了这两个数以外,其他任何数都可以选择被加或者被减,如果理解这个了,这个题就非常好做了。(只需要用数列中最大的数减去最小的数,然后对与剩下的n-2个数,正的就加,负的就减,显然,得到的结果就是最大的)
那么,怎样证明这个事实呢?
首先,n个数要变成1个数,一定会有一个数没有减过其他数,并且有且只有一个数被其他数减过。
除了这两个数以外,其他任何数都可以选择被加或者被减 ,证明如下:
假设这n个数为:
a1 a2 a3 a4 a5 x y z a6 a7
对于z来说,如果你想减他,只需要让y和z去结合,得到y-z,这个数列就变成了:a1 a2 a3 a4 a5 x y-z a6 a7 ,这就实现了减去z;
如果你想加他,只需要先让y和z先结合,得到(y-z),然后 让x和(y-z)结合,得到x-(y-z),即:x-y+z,这个数列就变成了:a1 a2 a3 a4 a5 x-y+z a6 a7 ,这就实现了加上z。
对于其他数也是同样的道理。
还有就是最终结果会爆int,所以要用long long。
AC_Code:
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 1000010
const double pi=acos(-1.0);
using namespace std;
int a[500010];
int main()
{
int n;
cin>>n;
for(int i=0; i<500010; i++)
a[i]=0;
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
if(n==1) //显然,如果n等1,那么结果就是a[0]
{
cout<<a[0];
return 0;
}
if(n==2)
{
cout<<fabs(a[1]-a[0]); //如果n等2,那么结果就是他们两个差的绝对值,即让大的那个是去结合小的那个数
return 0;
}
sort(a,a+n);
//int会爆
ll ans=a[n-1]-a[0]; //因为至少有一个数没有结合过,且有且只有一个数没有被结合过,就让最小的那个数做没有结合过的,让最大的那个数做没有被结合过的
for(int i=1; i<n-1; i++)
{
if(a[i]>=0) //正的就加
ans+=a[i];
else //负的就减
ans-=a[i];
}
cout<<ans;
return 0;
}