单调数据结构的其他应用
单调栈一般用来求解 NGE (Next Greater Element) 和类似问题,单调队列一般用来求解区间
P3503 [POI2010]Blocks
给定一个长为
的整数序列 ,有 次询问,每次给出一个正整数 ,可以进行如下操作:
- 每次选择一个大于
的正整数 ,将 减去 ,选择 或 中的一个加上 。 经过若干次操作后,问最长能够选出多长的一个区间,使得这个区间的每个数都不小于
。
。
首先注意到,一个区间合法(可以通过操作使得每个数都
感性理解,这个操作相当于一个元素把自己的值送给了与它相邻的元素,总和不变。如果平均值
问题转化为找到最大的
令
平衡树能做,但是多一个大常数
考虑什么样的
显然如果
于是我们发现合法的
在枚举
#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define per(i, s, e) for(int i = s, i##E = e; i >= i##E; --i)
#define F first
#define S second
#define int ll
#define gmin(x, y) (x = min(x, y))
#define gmax(x, y) (x = max(x, y))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double f128;
typedef pair<int, int> pii;
constexpr int N = 1e6 + 5;
int n, m, a[N], s[N];
signed main() {
#ifdef ONLINE_JUDGE
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#endif
cin >> n >> m;
rep(i, 1, n) cin >> a[i];
while(m--) {
int k; cin >> k;
rep(i, 1, n) s[i] = s[i - 1] + a[i] - k;
stack<int, vector<int>> stk;
stk.push(0);
rep(i, 1, n) if(s[i] < s[stk.top()]) stk.push(i);
int ans = 0, las = -1e18;
per(i, n, 1) {
if(s[i] <= las) continue;
while(!stk.empty() && s[i] >= s[stk.top()]) {
gmax(ans, i - stk.top());
stk.pop();
}
las = s[i];
}
cout << ans << ' ';
}
return 0;
}
P4954 [USACO09OPEN] Tower of Hay G
给定一个长为
的正整数序列 ,你需要把它划分成 个子区间 ,使得 ,问最大的 。
有一个从后往前的贪心,即最后一个单独分一组,前面的如果能分就分最短的,可以拿到 36 分。
虽然贪心是错的,但这给了我们一些启发,考虑从后往前 DP。设
于是我们得到了一个
依然是考虑什么样的
移项得到
考虑维护合法的
#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define per(i, s, e) for(int i = s, i##E = e; i >= i##E; --i)
#define F first
#define S second
#define int ll
#define gmin(x, y) (x = min(x, y))
#define gmax(x, y) (x = max(x, y))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double f128;
typedef pair<int, int> pii;
constexpr int N = 1e5 + 5;
int n, a[N], s[N], f[N], g[N];
inline int val(int i) {
return s[i] + g[i];
}
signed main() {
#ifdef ONLINE_JUDGE
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#endif
cin >> n;
rep(i, 1, n) cin >> a[i];
per(i, n, 1) s[i] = s[i + 1] + a[i];
deque<int> q;
q.push_back(n + 1);
per(i, n, 1) {
int t = q.back();
while(!q.empty() && val(q.back()) <= s[i])
t = q.back(), q.pop_back();
f[i] = f[t] + 1;
g[i] = s[i] - s[t];
q.push_back(t);
while(!q.empty() && val(q.front()) >= val(i))
q.pop_front();
q.push_front(i);
}
cout << f[1] << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类