DISJOINTSUB - Editorial

PROBLEM LINK:

Practice
Contest: Division 1
Contest: Division 2
Contest: Division 3
Contest: Division 4

Author: helloLad
Tester: wasd2401
Editorialist: iceknight1093

DIFFICULTY:

TBD

PREREQUISITES:

None

PROBLEM:

You have an array A.
You can choose some non-empty subsequence of it such that any pair of elements in the subsequence are non-adjacent; then choose some x\gt 0 and add x to all of them.

Is it possible to convert A to a sorted (in non-decreasing order) array by doing this at most once?

EXPLANATION:

If A is already sorted, nothing needs to be done and the answer is Yes.

Otherwise, there’ll exist some index i such that A_{i-1} \gt A_{i}.
For this index, notice that:

  • For A to be sorted in the end, we must increase A_{i}.
    However, A_{i-1} and A_{i+1} (if they exist) cannot be touched, since we can’t choose adjacent elements.
  • So, we must choose x such that A_i+x \geq A_{i-1}, and A_i+x \leq A_{i+1}.
    • Notice that this gives you lower and upper bounds on x: A_{i-1} - A_i \leq x \leq A_{i+1} - A_i.

Call an index i bad if A_i \gt A_{i-1}.
Let L = \max(A_{i-1} - A_i) across all bad indices i, and R = \min(A_{i+1} - A_i) across all bad indices i.
Then,

  • If L \leq R, the answer is Yes: you can choose any x between L and R and increase the value at all bad indices by x, at which point the array A will be sorted.
    • Note that for our move to be valid, we need to ensure that no two bad indices are adjacent, so that we can choose all of them simultaneously.
      However, if L \leq R is indeed true, you can show that no two bad indices can be adjacent — do you see why?
  • If L \gt R, the answer is No, since no matter which x you choose, some inequality at a bad index will fail.

TIME COMPLEXITY:

\mathcal{O}(N) per testcase.

CODE:

Author's code (C++)
#include "bits/stdc++.h"
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define all(x)      x.begin(), x.end()
#define pb          push_back
#define sz(x)       (int)(x.size())
#define ll          long long
#define fi          first
#define se          second
#define lbd         lower_bound
#define ubd         upper_bound

template <typename T>
using ordered_set = tree<T, null_type,
      less<T>, rb_tree_tag,
      tree_order_statistics_node_update>;

const int MOD = 1e9 + 7;
const double eps = 1e-10;
const long long INF = 1e18;
const int N = 2e5 + 10;


void solve() {
	int n;
	cin >> n;
	vector<int> v(n);
	for (int i = 0; i < n; ++i) {
		cin >> v[i];
	}

	int pre = v[0], x = 0;
	for (int i = 1; i < n; i++) {
		pre = max(pre, v[i]);
		x = max(x, pre - v[i]);
	}

	pre = v[0];
	bool okay = true;
	for (int i = 1; i < n; i++) {
		if (!okay && v[i] < pre) {
			cout << "No";
			return;
		} else if (v[i] < pre) {
			okay = false;
			v[i] += x;
		} else {
			okay = true;
		}
		pre = max(pre, v[i]);
	}

	cout << (is_sorted(v.begin(), v.end()) ? "Yes" : "No");
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	// freopen("input.in", "rt", stdin);
	// freopen("output.out", "wt", stdout);


	int tt = 1;
	cin >> tt;
	while (tt--) {
		solve();
		cout << '\n';
	}
	return 0;
}
Tester's code (C++)
/*

*       *  *  ***       *       *****
 *     *   *  *  *     * *        *
  *   *    *  ***     *****       *
   * *     *  * *    *     *   *  *
    *      *  *  *  *       *   **

                                 *
                                * *
                               *****
                              *     *
        *****                *       *
      _*     *_
     | * * * * |                ***
     |_*  _  *_|               *   *
       *     *                 *  
        *****                  *  **
       *     *                  ***
  {===*       *===}
      *  IS   *                 ***
      *  IT   *                *   *
      * RATED?*                *  
      *       *                *  **
      *       *                 ***
       *     *
        *****                  *   *
                               *   *
                               *   *
                               *   *
                                ***   

*/

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;
using namespace std;

#define osl tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update>
#define ll long long
#define ld long double
#define forl(i, a, b) for(ll i = a; i < b; i++)
#define rofl(i, a, b) for(ll i = a; i > b; i--)
#define fors(i, a, b, c) for(ll i = a; i < b; i += c)
#define fora(x, v) for(auto x : v)
#define vl vector<ll>
#define vb vector<bool>
#define pub push_back
#define pob pop_back
#define fbo find_by_order
#define ook order_of_key
#define yesno(x) cout << ((x) ? "YES" : "NO")
#define all(v) v.begin(), v.end()

const ll N = 2e5 + 4;
const ll mod = 1e9 + 7;
// const ll mod = 998244353;

ll modinverse(ll a) {
	ll m = mod, y = 0, x = 1;
	while (a > 1) {
		ll q = a / m;
		ll t = m;
		m = a % m;
		a = t;
		t = y;
		y = x - q * y;
		x = t;
	}
	if (x < 0) x += mod;
	return x;
}
ll gcd(ll a, ll b) {
	if (b == 0)
		return a;
	return gcd(b, a % b);
}
ll lcm(ll a, ll b) {
	return (a / gcd(a, b)) * b;
}
bool poweroftwo(ll n) {
	return !(n & (n - 1));
}
ll power(ll a, ll b, ll md = mod) {
	ll product = 1;
	a %= md;
	while (b) {
		if (b & 1) product = (product * a) % md;
		a = (a * a) % md;
		b /= 2;
	}
	return product % md;
}
void panipuri() {
	ll n, m = 0, k = -1, c = 0, sum = 0, q = 0, ans = 0, p = 1;
	string s;
	bool ch = true;
	cin >> n;
	vl a(n);
	forl(i, 0, n) {
		cin >> a[i];
	}
	vl v;
	forl(i,0,n-1){
		if(a[i]>a[i+1]) v.pub(i+1);
	}
	m=v.size();
	forl(i,0,m-1){
		if(a[v[i]]>a[v[i+1]]){
			yesno(0);
			return;
		}
	}
	a.pub(2e9);
	ll m1=0;
	forl(i,0,m){
		m1=max(m1,a[v[i]-1]-a[v[i]]);
	}
	ll m2=1e9;
	forl(i,0,m){
		m2=min(m2,a[v[i]+1]-a[v[i]]);
	}
	yesno(m1<=m2);
	return;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	#endif
	int laddu = 1;
	cin >> laddu;
	forl(i, 1, laddu + 1) {
		// cout << "Case #" << i << ": ";
		panipuri();
		cout << '\n';
	}
}
Editorialist's code (Python)
def solve(a):
    a = [0] + a + [10**10]
    lo, hi = 0, 10**10
    flag = 0
    for i in range(1, len(a)):
        if flag == 0:
            if a[i] < a[i-1]:
                flag = 1
                lo = max(lo, a[i-1] - a[i])
        else:
            if a[i] < a[i-2]:
                return 'No'
            flag = 0
            hi = min(hi, a[i] - a[i-1])
    if lo <= hi: return 'Yes'
    return 'No'

for _ in range(int(input())):
    n = int(input())
    a = list(map(int, input().split()))
    print(solve(a))
2 Likes

Let L= \max⁡(A_{i−1}−A_i) across all bad indices i, and R = \min(A_{i+1} - A_i) across all bad indices. I think this line is not correct.
Pls explain it.