D. Prefix Permutation Sums

发布时间 2023-10-06 16:47:53作者: 不o凡

D. Prefix Permutation Sums

吐槽:读题不仔细,还以为原数组的取值是任意的,最后看题解的时候才发现取值在[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;
}