我们有一个长度为 n n n 的数组。最初,每个元素都等于 0 0 0 ,第一个元素上有一个指针。
我们可以按任意顺序执行以下两种操作任意次数(可能为零):
- 如果指针不在最后一个元素上,则将指针当前所在的元素增加 1 1 1 。然后将其移动到下一个元素上。
- 如果指针不在第一个元素上,则将指针当前所在的元素减少 1 1 1 。然后移动到上一个元素。
但还有一条额外的规则。完成后,指针必须在第一个元素上。
给你一个数组 a a a 。请判断经过一些操作后是否可以得到 a a a 。
输入
第一行包含一个整数
t
(
1
≤
t
≤
1000
)
t (1≤t≤1000)
t(1≤t≤1000) 。 - 测试用例的数量。测试用例说明如下。
每个测试用例的第一行包含一个整数 n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) n (1≤n≤2⋅10^5) n(1≤n≤2⋅105) - 数组 a a a 的大小。
每个测试用例的第二行包含 n n n 个整数 a 1 , a 2 , … , a n ( − 1 0 9 ≤ a i ≤ 1 0 9 ) a_1,a_2,…,a_n ( −10^9≤a_i≤10^9 ) a1,a2,…,an(−109≤ai≤109) - 数组元素。
保证所有测试用例中 n n n 的总和不超过 2 ⋅ 1 0 5 2⋅10^5 2⋅105 。
输出
对于每个测试用例,如果经过某些操作后可以获得
a
a
a ,则打印 “Yes”(不带引号),否则打印 “No”(不带引号)
您可以在任何情况下输出 "Yes "和 “No”(例如,字符串 “yEs”、"yes "和 "Yes "将被视为肯定回答)。
对于这道题,多加思考多少能够想出来这道题的判断方式是和每一个数的操作一二次数是有关系的,但是这道题的终极解题结论还是很难推出来的。
假设我们给出
b
i
b_i
bi 为第
i
i
i 个元素进行操作
1
1
1 的次数,
c
i
c_i
ci 为第
i
i
i 个元素进行操作
2
2
2 的次数。
由于最终指针一定要回到第一个元素,所以
c
i
=
b
i
−
1
c_i = b_{i-1}
ci=bi−1,并且数组的和必须是
0
0
0。
对于同一个数的指针的移动,向右移动了 b i b_i bi 次,向左移动了 c i c_i ci 次,那么容易想到一定有 a i = b i − c i a_i = b_i - c_i ai=bi−ci。
那么联立两式可以得到 a i = b i − b i − 1 a_i = b_i - b_{i-1} ai=bi−bi−1,并且我们知道 a 1 = b 1 a_1 = b_1 a1=b1,那么我们可以求得 b i b_i bi。
求得b之后我们可以做什么?
我们已经知道了指针所有的向右移动的情况,那么我们可以说,如果
b
i
=
0
b_i = 0
bi=0,那么
b
i
b_i
bi 之后的所有
b
b
b 都应该等于
0
0
0 才能够符合情况,并且
b
i
b_i
bi 一定满足大于等于
0
0
0。
那么我们可以以此为依据进行判断。
CODE:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
#define int long long
int a[N];
int b[N];
void solve(){
int n;cin >> n;
for(int i = 1;i <= n;i++){
cin >> a[i];
b[i] = b[i-1] + a[i];
}
if(b[n] != 0){
cout << "NO\n";
return;
}
for(int i = 1;i <= n;i++){
if(b[i] < 0){
cout << "NO\n";
return;
}
}
bool vis0 = 0;
for(int i = 1;i <= n;i++){
if(vis0 && b[i] != 0){
cout << "NO\n";
return;
}
if(b[i] == 0)vis0 = 1;
}
cout << "YES\n";
}
signed main(){
int T;cin >> T;
while(T--){
solve();
}
return 0;
}