Skip to main content
  1. Posts/

CodeForces-1442A Extreme Subtraction

·3 mins·

CodeForces-1442A Extreme Subtraction #

题目大意 #

给定数组 $a$ , 每次可以选择它的一段前缀或后缀, 让这些元素 $-1$ . 询问能否将 $a$ 中元素全部变为 $0$ .

Solution 1 #

首先, 操作的顺序对结果没有影响, 因此, 可以把操作视作:

  • 对前缀进行操作
  • 对后缀进行操作

如果只对后缀进行操作就能让数组变为 $0$ , 那么这个数组必须是单调不减的. 假设经过前缀操作后, $a_i$ 变成了 $0$ , 应当有 $a_{i - 1} \geq a_i$ . 因此, 可以先找到 $a$ 的一个单调不增的最长前缀 $a_0, … ,a_l$, 显然这个前缀可以变为 $0$ . 类似, 我们可以找到 $a$ 单调不减的最长后缀 $a_r, …, a_{n - 1}$ . 此时问题转化为: 对 $a_{l + 1}, …, a_{r-1}$ 进行一系列前缀操作, 即让它们分别减去 $d_{l+1}, … ,d_{r - 1}$ , 要求 $a_l \geq d_{l+1} \geq…\geq d_{r - 1}$ , 且 $0 = a_l \leq a_{l+1} - d_{l+1} \leq …\leq a_{r - 1} - d_{r - 1}\leq a_r$ . 遍历 $a_{l+1}, …, a_{r - 1}$ , 逐步寻找可行的 $d$ 即可. 这是一个构造性的解法. 代码如下:

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

int main() {
	int t;
	cin>>t;
	while (t--) {
		int n;
		cin>>n;
		int a[n];
		for (int i = 0; i < n; i++) {
			cin>>a[i];
		}
		int l;
		for (l = 0; l < n - 1;) {
			if (a[l + 1] <= a[l]) {
				l++;
			}
			else {
				break;
			}
		}
		int r;
		for (r = n - 1; r > 0;) {
			if (a[r - 1] <= a[r]) {
				r--;
			}
			else {
				break;
			}
		}
		if (r - l <= 1) {
			cout<<"YES"<<endl;
			continue;
		}
		bool ans = true;
		int d = a[l];
		a[l] = 0;
		for (int i = l + 1; i < r; i++) {
			d = min(d, min(a[i], a[i] - a[i - 1]));
			a[i] -= d;
			if (a[i] < a[i - 1]) {
				ans = false;
				break;
			}
		}
		if (a[r - 1] > a[r]) {
			ans = false;
		}
		printf("%s\n", ans? "YES": "NO");
	}
	return 0;
}

Solution 2 #

考虑原数组的差分数组. 如果最终数组元素全为 $0$ , 那么差分数组的元素同样全为 $0$ . 考虑两种操作对差分数组 $d$ 的影响:

  • 对前缀 $a_0, …, a_i$ 进行操作, 那么 $d_0$ 减 $1$ 且 $d_{i+1}$ 加 $1$
  • 对后缀 $a_i, …, a_{n-1}$ 进行操作, 那么 $d_{i}$ 减 $1$ (且 $d_{n}$ 加 $1$ , 不过 $d_{n}$ 与本题无关)

由此, 通过前缀操作可以将 $d$ 中的负数 (首项除外) 变为 $0$ , 通过后缀操作可以将 $d$ 中的正数变为 $0$ . 所以, 当且仅当 $d_0 \geq \sum_{v\in d, v < 0}\vert v\vert$ 时, 可以通过操作使得数组元素全部变为 $0$ . 代码如下:

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        int a[n];
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        int res = 0;
        for (int i = n - 1; i >= 1; i--) {
            a[i] -= a[i - 1];
            if (a[i] < 0) {
                res -= a[i];
            }
        }
        printf("%s\n", a[0] >= res ? "YES" : "NO");
    }
    return 0;
}