大致思路:
由于体力值的存在每次只能够着[i,i+k]之间的宝石,题目要求输出最大字典序,且两个魔力值相同的宝石不能挨着,因此采用贪心策略每次取[i,i+k]中最大的宝石,但若魔力值与前一个宝箱中宝石相同则取次大的,若区间[i,i+k]内有多个符合条件的宝石则取距离宝箱最近的宝石,这样体力值消耗最小。体力值的消耗又会改变区间[i,i+k]的大小
关键:用什么维护这样区间呢?
set容器和线段树都可以维护区间的最大值,且实现在o(logn)时间完成区间的增加,删除。
流程:对于每个宝箱:先维护区间->贪心找出宝石->放入宝箱更新信息->维护区间->贪心找出宝石->......
样例
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100000 + 100;
struct Node {
int a, idx;//a存到是宝石值,idx是下标
};
bool operator<(const Node &a, const Node &b) {
return a.a == b.a ? a.idx < b.idx : a.a > b.a;
}
//视频中只用一句辅助变量代替合适吗?
int n, k, idx=1;//此idx非彼idx,应该说set容器中存的元素为[i,idx),即idx=k+i+1
int ans[maxn], a[maxn];//ans存宝箱,a存宝石
bool vis[maxn];
set<Node> st;
set<Node>::iterator it;//定义迭代器 it
int main() {
// #ifdef ExRoc//如果编译的时候定义了这个宏就执行中间这段代码,endif类似结束符
// freopen("test.txt", "r", stdin);//将标准输入重定向到text文件中,方便从文件中读取测试数据。
// #endif
// ios::sync_with_stdio(false);//关闭c++标准流与c标准流的同步(能保证混用时顺序正确),提高速度
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
memset(ans, -1, sizeof(ans));//初始化宝箱为空
for (int i = 1; i <= n; ++i) {//第i个宝箱
//idx = max(idx, i);
while (idx <= n && idx - i <= k) {//把i到i+k内的宝石放入维护的集合里面去
if (!vis[idx]) {
st.insert({a[idx], idx});//宝石插入维护的集合里面去
}
++idx;//结束的时候idx=i+k+1,表示的是集合中最后一个元素的后一个元素
}
while (idx - 1 >= i && idx - 1 - i > k) {//若k变小了,则删除其中元素,idx-1是因为最开始会更新idx至少从i开始,宝箱向后移动了一位
st.erase({a[idx - 1], idx - 1});
--idx;//结束的时候idx=i+k+1;
}
if (!st.empty()) {//若维护的集合不为空就放宝石,只要前一个宝箱的宝石与集合中最大元素不等(判断含当前宝库为空)我就放进去,相等我就放次大的。
if ( ans[i - 1] != st.begin()->a) {
it = st.begin();
} else {
it = st.upper_bound({ans[i - 1], n});
}
if (it != st.end()) {//如果(存在次大的)我就放,并标记这个宝石已经放入宝箱,更新体力值并将其从维护的集合中删除
ans[i] = it->a;
vis[it->idx] = true;
k -= it->idx - i;
st.erase(it);
}
st.erase({a[i], i});//删除元素应放在非空中
}
}
for (int i = 1; i <= n; ++i) {
cout << ans[i] << " ";
}
cout << endl;
return 0;
}
堆我感觉有点机会,它维护最大值,可以实现在o(logn)时间完成插入,感觉删除需要重新建堆也就是o(n),没试过。
暴力不可行:若采用暴力的方法每次都需要遍历区间也就是o(n)的。
本代码参考该视频代码的基础上做了一些细微调整
参考视频:b站up ExRoc_
参考代码:在其封印宝石视频解析下方
吐槽:视频解题思路清晰,但视频对于代码的解析一点都不详略得当,某些东西可有可无,还有变量的重名让真的让人头大。在这方面个人感觉b站董晓算法代码很精炼。