【Codeforces Round #696 (Div. 2) D】Cleaning

题目链接

链接

翻译

你可以选择相邻的两个都不为空的石头堆,从两个石头堆(每个石头堆中有多个石头)中都拿去一个石头。

你可以进行无数次这样的操作,问你最终能否将所有的石头都拿走。

石头是在一条直线上排列的,从左到右标号为 \(1\)\(n\)

题解

会发现第一个位置上的石头,只能通过拿堆 \(1\) 和堆 \(2\) 全部拿走。

然后堆 \(1\) 全拿完之后,堆 \(2\) 变成新的堆 \(1\) 了,所以也只能拿头两堆的石头。

以此类推,我们就可以这样每次贪心地拿头两堆完成一次 \(check\),看是否能够在不使用超能力的情况下拿走全部石头了。

如果不能够做到的话,就需要使用超能力了。

这里先提醒一点,我们同样可以从最后一堆开始拿起,因为最后一堆也只能通过每次拿倒数的两堆实现全都拿走。

因此,我们可以设 \(pre_i\)\(suf_i\) 分别表示 \(1..i-1\) , \(i+1..n\) 这些堆的石头全部被拿走了,然后第 \(i\) 堆石头剩余的石头数目。

会发现我们交换相邻的两堆石头 \(i\)\(i+1\), 问题就转化为 \(pre_{i-1}\)\(a[i+1]\) 以及 \(a[i]\)\(suf_{i+2}\) 这四个位置的石头堆能否全都

拿走了,因为 \(1..i-2\)\(i+3..n\) 这些位置上的石头能否拿走都不会受这次 \(swap\) 的影响。

\(\mathcal{O}(N)\) 枚举交换位置即可。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int N = 2e5;

int T, n;
int a[N + 10],pre[N+10],suf[N+10];

bool ok(vector<int> v) {
	int len = v.size();
	for (int i = 0; i <= len - 2; i++) {
		if (v[i] < 0) {
			return false;
		}
		v[i + 1] -= v[i];
		v[i] = 0;
	}
	for (int x : v) {
		if (x != 0) {
			return false;
		}
	}
	return true;
}

int main() {
	#ifdef LOCAL_DEFINE
		freopen("in.txt", "r", stdin);
	#endif // LOCAL_DEFINE
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> T;
	
	while (T--) {
		cin >> n;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
		}
		pre[1] = a[1];
		for (int i = 2; i <= n; i++) {
			if (pre[i - 1] < 0) {
				pre[i] = -1;
				continue;
			}
			pre[i] = a[i] - pre[i - 1];
		}
		suf[n] = a[n];
		for (int i = n - 1; i >= 1; i--) {
			if (suf[i + 1] < 0) {
				suf[i] = -1;
				continue;
			}
			suf[i] = a[i] - suf[i + 1];
		}
		if (pre[n] == 0) {
			cout << "YES" << endl;
			continue;
		}
		bool finalOK = false;
		for (int i = 1; i <= n - 1; i++) {
			//swap(a[i],a[i+1])
			vector<int> v(0);
			if (i > 1) {
				v.push_back(pre[i - 1]);
				if (pre[i - 1] < 0) {
					continue;
				}
			}
			v.push_back(a[i+1]);v.push_back(a[i]);
			if (i <= n - 2) {
				if (suf[i + 2] < 0) {
					continue;
				}
				v.push_back(suf[i+2]);
			}
			if (ok(v)) {
				finalOK = true;
				break;
			}
		}
		if (finalOK) {
			cout << "YES" << endl;
		}
		else {
			cout << "NO" << endl;
		}
	}
	return 0;
}
posted @ 2021-03-02 21:46  AWCXV  阅读(50)  评论(0编辑  收藏  举报