题目大意
给出一个序列,每次可以任意选择相邻的两个数,使得两个数都减去二者的最小值。现在可以最多交换两个相邻的数,问能否将整个序列全部消为0。
解题思路
假设不能交换,我们可以从前向后依次进行上述操作,设数组 p r e [ i ] = a [ i ] − p r e [ i − 1 ] , p r e [ 0 ] = 0 pre[i] = a[i] - pre[i-1],pre[0] = 0 pre[i]=a[i]−pre[i−1],pre[0]=0,如果到最后一步结束后 p r e [ n ] = 0 pre[n] = 0 pre[n]=0,那么成功消成 0 0 0;显然从后向前依次进行也是同理的。
若序列不能消成0代表从前向后到达的某个位置, a [ i ] < p r e [ i − 1 ] a[i] < pre[i-1] a[i]<pre[i−1]。但是 [ 1 , i − 1 ] [1,i-1] [1,i−1]已经都能消成 0 0 0,对答案没有影响,可以看做前面这部分最终变成了 p r e [ i − 1 ] pre[i-1] pre[i−1]一个数;同理从后向前消时,序列不能消成0代表到达的某个位置 a [ i ] < s u b [ i + 1 ] a[i] < sub[i+1] a[i]<sub[i+1]。而 [ i + 1 , n ] [i+1,n] [i+1,n]已经都能消成 0 0 0无影响,可以看做后面这部分最终变成了 s u b [ i + 1 ] sub[i+1] sub[i+1]一个数。
上述分析启发我们,枚举每对 ( a [ i ] , a [ i + 1 ] ) (a[i],a[i+1]) (a[i],a[i+1])并假设交换他们的位置,那么我们只要知道 p r e [ i − 1 ] , s u b [ i + 2 ] pre[i-1],sub[i+2] pre[i−1],sub[i+2],那么就变成了四个数去消,就比较简单了。预处理 p r e , s u b pre,sub pre,sub数组时,如果得到负数那么后面的结果都置为负数即可,判断时只要 p r e [ i − 1 ] , s u b [ i + 2 ] pre[i-1],sub[i+2] pre[i−1],sub[i+2]有一个小于0那么就是无效的判断。
PS:注意判断 p r e [ i − 1 ] < = a [ i + 1 ] & & s u b [ i + 2 ] < = a [ i ] pre[i - 1] <= a[i + 1] ~~\&\& ~~ sub[i + 2] <= a[i] pre[i−1]<=a[i+1] && sub[i+2]<=a[i],否则可能相减都是负数恰好相等,而倒在 t e s t 2 test2 test2
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef pair<int, int> pii;
#define ENDL "\n"
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int a[maxn], pre[maxn], sub[maxn];
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t, n;
cin >> t;
while (t--) {
cin >> n;
for (int i = 0; i <= n + 1; i++) pre[i] = sub[i] = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (pre[i - 1] < 0 || pre[i - 1] > a[i]) pre[i] = -1;
else pre[i] = a[i] - pre[i - 1];
}
for (int i = n; i >= 1; i--) {
if (sub[i + 1] < 0 || sub[i + 1] > a[i]) sub[i] = -1;
else sub[i] = a[i] - sub[i + 1];
}
//for (int i = 1; i <= n; i++) cout << pre[i] << " " << sub[i] << endl;
if (n == 1) {
cout << "NO" << ENDL;
continue;
}
if (!pre[n]) {
cout << "YES" << ENDL;
continue;
}
bool ok = 0;
for (int i = 1; i < n; i++) {
if (pre[i - 1] < 0 || sub[i + 2] < 0) continue;
if (pre[i - 1] <= a[i + 1] && sub[i + 2] <= a[i] && a[i + 1] - pre[i - 1] == a[i] - sub[i + 2]) {
ok = 1;
break;
}
}
if (ok) cout << "YES" << ENDL;
else cout << "NO" << ENDL;
}
return 0;
}