吐槽:读题不仔细,还以为原数组的取值是任意的,最后看题解的时候才发现取值在[1,n],当时因为看不懂直接跳过了
题意:给你一个缺了一个的前缀和数组,让你判断是否存在原数组,取值[1,n],每个数只存在一次
可以分类讨论
1 缺少最后一个前缀和
2 缺少前面的前缀和
方法:
我们设1加到n为sum
特判:
如果给定的数组的最后一个元素大于sum,那么不存在
对于1:(最后一个元素小于sum)
1.如果sum-a[n-1]>n,说明不存在,因为[1,n]不存在这个数
2.然后计算每一个相差的值,如果没有重复,则存在
对于2:(sum==a[n-1])
1.分析可知,在a[i-1],a[i],a[i+1],如果a[i]消失,那么a[i+1]-a[i-1],就是两个数的和
2.这两数和可能大于n,也可能小于n(如果小于n,则会有两个数重复),记录这两个数的和
3.从1到n遍历,看那个数还没有遍历到,将其累加起来
4.如果最后累加的和等于两数和,则存在
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define LL long long
LL a[N],cnt[N];
void solve() {
int n;
cin >> n;
memset(cnt, 0, sizeof cnt);
for (int i = 1; i < n; i++) cin >> a[i];
LL sum = 1LL*n * (1LL*n + 1) / 2;
if (a[n - 1] > sum) {//大于最大值,不满足直接退出
cout << "NO\n";
return;
}
if (a[n - 1] < sum) {//缺少最后一个前缀和
if (sum - a[n - 1] > n) {//保证相差在[1,n]
cout << "NO\n";
return;
}
int ans = 1;//记录出现次数
cnt[sum - a[n - 1]]++;
for (int i = 1; i < n; i++) {
int x = a[i] - a[i - 1];
if (!cnt[x]) {
cnt[x] = 1;
ans++;
}
}
if (ans == n) {
cout << "YES\n";
return;
}
else cout << "No\n";
return;
}
//缺少前面的前缀和
int mx = 0;
for (int i = 1; i < n; i++) {//寻找max值
int x = a[i] - a[i - 1];
if (x > n) mx = x;
else if (cnt[x] == 1) mx = x;
cnt[x]++;
}
int k = 0;
for (int i = 1; i <= n; i++) {
if (cnt[i] == 0) k += i;//没有标记的数
}
if (k == mx) {//如果没有标记的两数等于最大值,那么存在
cout << "YES\n";
}
else cout << "NO\n";
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}