1. 程式人生 > 其它 >CodeCraft-22 and Codeforces Round #795 (Div. 2)

CodeCraft-22 and Codeforces Round #795 (Div. 2)

比賽連結:

https://codeforces.com/contest/1691

D. Max GEQ Sum

題意:

給定一個序列 \(a\),問對於 \(1 <= i <= j <= n\),是否都滿足 \(max(a_i, a_{i + 1}, ... , a_j) >= \sum_{k = i}^{j}\)

思路:

對於每一個 \(i\),可以通過單調棧\(O(n)\) 的時間複雜度找到以 \(a_i\) 為最大值的一個區間,這樣只需找到這個區間中最大的區間和就可以判斷是不是滿足條件。可以通過線段樹或者ST表找到區間中最大的區間和。

程式碼:

線段樹

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL N = 2e5 + 10, inf = 1e18 + 10;
LL T = 1, w[N], s[N], L[N], R[N], n;
struct segt{
	LL l, r, mx, mn;
}tr[N * 4];
void pushup(LL u){
	tr[u].mx = max(tr[u << 1].mx, tr[u << 1 | 1].mx);
	tr[u].mn = min(tr[u << 1].mn, tr[u << 1 | 1].mn);
}
void build(LL u, LL l, LL r){
	if (l == r){
		tr[u] = {l, r, s[r], s[r]};
		return;
	}
	tr[u] = {l, r, -inf, inf};
	LL mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	pushup(u);
}
LL queryMx(LL u, LL l, LL r){
	if (tr[u].l >= l && tr[u].r <= r) return tr[u].mx;
	LL mid = tr[u].l + tr[u].r >> 1, mx = -inf;
	if (l <= mid) mx = max( mx, queryMx(u << 1, l, r) );
	if (r > mid) mx = max( mx, queryMx(u << 1 | 1, l, r) ) ;
	return mx;
}
LL queryMn(LL u, LL l, LL r){
	if (tr[u].l >= l && tr[u].r <= r) return tr[u].mn;
	LL mid = tr[u].l + tr[u].r >> 1, mn = inf;
	if (l <= mid) mn = min( mn, queryMn(u << 1, l, r) );
	if (r > mid) mn = min( mn, queryMn(u << 1 | 1, l, r) ) ;
	return mn;
}
void solve(){
	cin >> n;
	for (int i = 1; i <= n; i ++ ){
		cin >> w[i];
		s[i] = s[i - 1] + w[i];
	}
	build(1, 1, n);
	stack <LL> stk;
	w[n + 1] = w[0] = inf;
	for (int i = 1; i <= n + 1; i ++ ){
		while (stk.size() && w[stk.top()] < w[i]){
			R[stk.top()] = i;
			stk.pop();
		}
		stk.push(i);
	}
	while ( stk.size() ) stk.pop();
	for (int i = n; i >= 0; i -- ){
		while (stk.size() && w[stk.top()] < w[i]){
			L[stk.top()] = i;
			stk.pop();
		}
		stk.push(i);
	}
	for (int i = 1; i <= n; i ++ ){
		LL mn = queryMn(1, L[i], i - 1);
		if (L[i] == 0)
			mn = min(0LL, mn);
		if ( w[i] < queryMx(1, i, R[i] - 1) - mn ){
			cout << "NO\n";
			return;
		}
	}
	cout << "YES\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin >> T;
	while (T -- )
		solve();
	return 0;
}

ST表

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL N = 2e5 + 10, inf = 1e18 + 10;
LL T = 1, w[N], s[N], L[N], R[N], mn[N][31], mx[N][31], n;
void ST(){
	for (int i = 0; i <= n; i ++ )
		mx[i][0] = mn[i][0] = s[i];
	LL k = log2(n);
	for (int j = 1; j <= k; j ++ )
		for (int i = 0; i + (1 << j) - 1 <= n; i ++ ){
			mx[i][j] = max(mx[i][j - 1], mx[i + ( 1 << (j - 1) )][j - 1]);
			mn[i][j] = min(mn[i][j - 1], mn[i + ( 1 << (j - 1) )][j - 1]);
		}
}
LL queryMax(LL l, LL r){  //查詢最大值
	LL k = log2(r - l + 1);
	return max(mx[l][k], mx[r - (1 << k) + 1][k]);
}
LL queryMin(LL l, LL r){  //查詢最小值
	LL k = log2(r - l + 1);
	return min(mn[l][k], mn[r - (1 << k) + 1][k]);
}
void solve(){
	cin >> n;
	for (int i = 1; i <= n; i ++ ){
		cin >> w[i];
		s[i] = s[i - 1] + w[i];
	}
	ST();
	stack <LL> stk;
	w[n + 1] = w[0] = inf;
	for (int i = 1; i <= n + 1; i ++ ){
		while (stk.size() && w[stk.top()] < w[i]){
			R[stk.top()] = i;
			stk.pop();
		}
		stk.push(i);
	}
	while ( stk.size() ) stk.pop();
	for (int i = n; i >= 0; i -- ){
		while (stk.size() && w[stk.top()] < w[i]){
			L[stk.top()] = i;
			stk.pop();
		}
		stk.push(i);
	}
	for (int i = 1; i <= n; i ++ ){
		if ( w[i] < queryMax(i, R[i] - 1) - queryMin(L[i], i - 1) ){
			cout << "NO\n";
			return;
		}
	}
	cout << "YES\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin >> T;
	while (T -- )
		solve();
	return 0;
}