题目大意:
在正整数数组中移动一个元素到任意位置(可以不移动),判断能不能使数组前一部分之和等于后一部分。
思路:
用 sum 记录数组元素之和, cur记录当前前缀和, 若 cur > sum-cur (前一部分大于后一部分) ,在前一部分中寻找(把前一部分的元素全部放入集合中)一个元素移动到后一部分,使两部分各自之和相等。即 cur - x = sum - cur + x ,
2x = 2cur - sum ; (注:寻找时,寻找2倍的数,除2的话会向下取整可能会导致找不到要找的数);
即 在集合中插入时插入两倍的数值(2*a[i]),寻找时也是寻找两倍的数值(2*cur - sum);
上面的情况为将前一部分中的一个数移动到后一部分,还有一种情况是将后一部分的一个数移动到前一部分。即把数组逆置之后,再进行一遍上述情况;
还有一种情况为无需移动,直接遍历就能找到一个数使前后两部分各自之和相等,
即 cur == sum-cur
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
ll a[N];
set <ll> s;
bool ans;
int main(){
int t;
cin>>t;
while(t--){
int n;
ll cur=0, sum=0;
ans=false;
s.clear();
cin>>n;
for(int i=0;i<n;i++) {
cin>>a[i];
sum+=a[i];
}
for(int i=0;i<n;i++){
cur+=a[i];
s.insert(2*a[i]);
if(sum-cur < cur)
{
if(s.count((2*cur-sum))) {
ans = true;
break;
}
}
else if(sum-cur == cur){
ans=true;
break;
}
}
reverse(a,a+n);
s.clear();//记得重置
cur=0;
for(int i=0;i<n;i++){
cur+=a[i];
s.insert(2*a[i]);
if(sum-cur < cur)
{
if(s.count((2*cur-sum))) {
ans = true;
break;
}
}
else if(sum-cur == cur){
ans=true;
break;
}
}
if(ans) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}