bzoj2802 [Poi2012]Warehouse Store 贪心+堆

题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=2802

题解

我一开始想到了一个比较麻烦的做法。

把每一天按照 \(b_i\) 从小到大排序,\(b_i\) 小的优先选。然后扣除库存的话,优先扣除在当前这个 \(b_i\) 的位置前面最近的库存。

这个可以使用树状数组来判断能不能选,然后扣除库存的时候因为每一个日子的库存只会被扣光一次,所以可以暴力跳,但是不要走已经被扣光的点,所以使用并查集跳过这些不应该经过的点。

但是很显然这个做法很麻烦,写起来细节和码量应该都不小。


所以我们不妨换一个做法。但是我实在想不到除了我上面的做法以外还有别的什么做法。

所以去拜读了一下题解。捂脸

大概意思就是说,我们很显然会有一个非常错误的做法:对于每一位能选就选。

使这个算法错误的情况是有可能存在一个点,选了当前这个以后可能会导致后面多于一个可选方案失效。(贪心策略很多时候成立的条件是以一换一

但是不要轻易放弃这个做法!

我们想一想怎么更正这个做法。

如上文所述,使这个算法错误的情况是有可能存在一个点,选了当前这个以后可能会导致后面多于一个可选方案失效。那么我们是不是可以找出一个方法把失效方案重新变得有效呢。

既然贪心策略很多时候成立的条件是以一换一,那么我们其实可以在当前这个点不选的时候,把这个东西和目前已经选过的最大的需求量比较。如果当前这个小的话,我们其实可以把当前这个拿去替换掉之前的最大的,因为这样一定可以使剩下的总库存变大。

至于之前的最大的需求量怎么找,就是用一个堆来维护一下。


上面两个做法的时间复杂度都是 \(O(n\log n)\)

#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 250000 + 7;
int n;
int a[N], b[N], aa[N];
std::priority_queue<pii> q;
inline void work() {
ll sum = 0;
int ans = 0;
for (int i = 1; i <= n; ++i) {
sum += a[i];
if (sum >= b[i]) sum -= b[i], q.push(pii(b[i], i));
else if (!q.empty() && sum + q.top().fi >= b[i] && b[i] <= q.top().fi) sum += q.top().fi - b[i], q.pop(), q.push(pii(b[i], i));
}
while (!q.empty()) aa[++ans] = q.top().se, q.pop();
std::sort(aa + 1, aa + ans + 1);
printf("%d\n", ans);
for (int i = 1; i <= ans; ++i) printf("%d%c", aa[i], " \n"[i == ans]);
}
inline void init() {
read(n);
for (int i = 1; i <= n; ++i) read(a[i]);
for (int i = 1; i <= n; ++i) read(b[i]);
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
posted @   hankeke303  阅读(132)  评论(0编辑  收藏  举报
编辑推荐:
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
阅读排行:
· 为DeepSeek添加本地知识库
· 精选4款基于.NET开源、功能强大的通讯调试工具
· DeepSeek智能编程
· 大模型工具KTransformer的安装
· [计算机/硬件/GPU] 显卡
历史上的今天:
2018-10-28 HEOI2015 兔子与樱花
2018-10-28 ZJOI2006 三色二叉树
2018-10-28 牛客网NOIP赛前集训营-提高组(第七场)C-洞穴
2018-10-28 牛客网NOIP赛前集训营-提高组(第七场)B-随机生成树
2018-10-28 牛客网NOIP赛前集训营-提高组(第七场)A-中国式家长 2
点击右上角即可分享
微信分享提示