题意:给一个长度为n的非负数列,每次可以选两个数同时减1,问能否将整个数列的数全部归零。
题解:第一波猜结论猜错了(只猜中第一个必要条件“所有数之和为偶数”,也考虑过如果只有两个数那么必须相等)。其实再多想一步就可以发现如果有多个数,那么最大的那个数在不能超过剩下的之和。超过了的话这个最大数无法归零。现在想想如何证明不超过就一定可以归零。
假设最大数为a,次大数为b,剩余的数之和为sum,剩余的数中最大的为c(原数列第三大),我们先用a“消耗”b(同时使a,b减1)直到b==c(这一步一定可以实现,因为a>b>b-c)这时再用a去消耗a, b, c以外其他数,可能有两种情况:
①如果a变为0,那么这个局面再一次成为一个“所有数之和为偶数且最大数不超过剩下数之和”的局面(b和c同时为当前最大数),而数的个数减少了一个,于是接着递归处理就好
②如果a还剩下(a, b, c之外所有数都已经变为0),由于当前所有数之和依然为偶数且b==c,可以得知此时a是偶数,那么之后就(a, b)减一次,(a, c)减一次轮着来直到a归零(一定可以,因为a<b+sum),然后(b, c)一直减到0即可
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cassert>
using namespace std;
typedef long long ll;
const int N=1e5+4;
int n;
ll a[N];
ll mx,sum;
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void smax(ll &x,ll y) {
x=x<y?y:x;
}
int main() {
n=read();
for (register int i=1;i<=n;++i) {
a[i]=read();
sum+=a[i];
smax(mx,a[i]);
}
if (!(sum&1)&&mx<=sum-mx) puts("YES");
else puts("NO");
return 0;
}