CodeForces-1691D Max GEQ Sum
Max GEQ Sum#
单调栈 + 线段树
这题非常值得
思路:
假设我们此时的最大值为 ,那么我们考虑不等式是否成立时,就应该考虑一个最大的区间 ,在这里找有没有不符合不等式的情况出现
最大区间 : 且
如何找到不符合不等式的情况:
->
因为我们只要在 上找到一个任意的包含 的区间,使得其和大于 即可,因此我们只需要考虑其两边任意一个区间大于 0 即可
-> 或
实现:
- 找到区间 ,即找到每个 左右两边第一个大于 的数
这里考虑使用单调栈,栈底到栈顶,从大到小维护,碰到比当前数字小的就弹出
- 找不等式不成立的情况
这里我们改成 或 来实现
我们考虑区间和的时候使用前缀和 维护,以 为例:
不难发现,在查找的区间中, 是不变的,因此我们可以转化成为在 中,找一个 的最小值
这个查找可以考虑用线段树来实现,同理对于右边的情况可以用查找最大值来实现
单调栈:
总体线段树查询:
时间复杂度:
挺可惜没想到线段树 + 前缀和维护,想半天一直卡在找的上面
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
ll num[maxn], sum[maxn];
int pre_l[maxn], pre_r[maxn];
void st_solve(int n)
{
stack<int>st;
st.push(0);
num[0] = num[n+1] = inf;
for(int i=1; i<=n; i++)
{
while(num[st.top()] <= num[i]) st.pop();
pre_l[i] = st.top();
st.push(i);
}
while(st.size()) st.pop();
st.push(n+1);
for(int i=n; i>=1; i--)
{
while(num[st.top()] <= num[i]) st.pop();
pre_r[i] = st.top();
st.push(i);
}
num[0] = num[n+1] = 0;
}
struct node
{
ll maxx, minn;
}tr[maxn << 2];
void push_up(int now)
{
tr[now].maxx = max(tr[now << 1].maxx, tr[now << 1 | 1].maxx);
tr[now].minn = min(tr[now << 1].minn, tr[now << 1 | 1].minn);
}
void build(int now, int l, int r)
{
if(l == r)
{
tr[now].maxx = tr[now].minn = sum[l];
return;
}
int mid = l + r >> 1;
build(now << 1, l, mid);
build(now << 1 | 1, mid + 1, r);
push_up(now);
}
ll query_min(int now, int l, int r, int L, int R)
{
if(L <= l && r <= R)
return tr[now].minn;
int mid = l + r >> 1;
ll ans = inf;
if(L <= mid) ans = query_min(now << 1, l, mid, L, R);
if(R > mid) ans = min(ans, query_min(now << 1 | 1, mid + 1, r, L, R));
return ans;
}
ll query_max(int now, int l, int r, int L, int R)
{
if(L <= l && r <= R)
return tr[now].maxx;
int mid = l + r >> 1;
ll ans = -inf;
if(L <= mid) ans = query_max(now << 1, l, mid, L, R);
if(R > mid) ans = max(ans, query_max(now << 1 | 1, mid + 1, r, L, R));
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
for(int i=1; i<=n; i++)
{
cin >> num[i];
sum[i] = sum[i-1] + num[i];
}
st_solve(n);
build(1, 0, n);
int f = 1;
for(int i=1; i<=n && f; i++)
{
int l = pre_l[i];
int r = pre_r[i];
ll l_val = query_min(1, 0, n, l, i - 1);
ll r_val = query_max(1, 0, n, i, r - 1);
if(max(sum[i] - l_val, r_val - sum[i-1]) > num[i]) f = 0;
}
if(f) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
分类:
题解
标签:
单调栈 && 单调队列
, 线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现