比赛链接:
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;
}