CodeCraft-22 and Codeforces Round #795 (Div. 2)
阿新 • • 發佈:2022-06-05
比賽連結:
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; }