给定一个长度为 移动元素(秋季每日一题 35)_前缀和 的正整数数组 移动元素(秋季每日一题 35)_思维题_02

你需要选择其中一个元素,将其移动至数组中的任意位置(也可以留在原位置)。

我们的目标是,在移动元素操作完成以后,将数组分为前后两个非空部分,并使前一部分的各元素之和等于后一部分的各元素之和。

请问,该目标能否达成?

输入格式
第一行包含整数 移动元素(秋季每日一题 35)_数组_03,表示共有 移动元素(秋季每日一题 35)_数组_03

每组数据第一行包含整数 移动元素(秋季每日一题 35)_前缀和

第二行包含 移动元素(秋季每日一题 35)_前缀和 个整数 移动元素(秋季每日一题 35)_思维题_02

输出格式
每组数据输出一行结果,目标可以达成,则输出 ​​​YES​​​,否则输出 ​​NO​​。

数据范围
移动元素(秋季每日一题 35)_前缀和_08
移动元素(秋季每日一题 35)_思维题_09
移动元素(秋季每日一题 35)_前缀和_10
同一测试点内所有 移动元素(秋季每日一题 35)_前缀和 的和不超过 移动元素(秋季每日一题 35)_i++_12

输入样例:

3
3
1 3 2
5
1 2 3 4 5
5
2 2 3 4 5

输出样例:

YES
NO
YES

分类讨论

  1. 要移动的元素的原位置与目的位置都在分割线一边
    则直接找到 移动元素(秋季每日一题 35)_数组_13
  2. 要移动的元素的原位置与目的位置在分割线的两边
    则算出前缀和与后缀和
    移动元素(秋季每日一题 35)_哈希表_14
    移动元素(秋季每日一题 35)_前缀和_15
    枚举 移动元素(秋季每日一题 35)_思维题_16 判断 移动元素(秋季每日一题 35)_i++_17 是否在 移动元素(秋季每日一题 35)_思维题_18 ~ 移动元素(秋季每日一题 35)_数组_19
#include<iostream>
#include<unordered_set>

using namespace std;

typedef long long LL;

const int N = 100010;

int n;
int a[N], b[N];
LL s[N];

bool check(int w[]){


for(int i = 1; i <= n; i++) s[i] = s[i-1] + w[i];
if(s[n] % 2) return false;

unordered_set<LL> S;
S.insert(0);
for(int i = 1; i <= n; i++){

S.insert(w[i]);
if(S.count(s[i] - s[n] / 2)) return true;
}

return false;
}

int main(){

int t;
scanf("%d", &t);

while(t--){

scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
b[n-i+1] = a[i];
}

if(check(a) || check(b)) puts("YES");
else puts("NO");
}

return 0;
}