Description
Input
Output
Hint
Solution
可以撤销的贪心,妙啊
考试的时候没想到,思路很神奇。
贪心地做,用一个堆维护最大的点。由于不能连续地选,那么我们选了一个点i之后就删掉前面的点pre[i]和后面的点nex[i]。但是这样会错因为不一定是最优的,于是需要每次删点之后新建一个权值为v[pre[i]]+v[nex[i]]-v[i]的点,表示选了pre[i]和nex[i]而不选i,意味着只选i的操作是可以撤销的。这样每次一定多选一个点,选完m个一定是最优的
Code
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <queue>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define erg(i, st) for (int i = ls[st]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) ((x)>(y)?(x):(y))
#define min(x, y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<(0)?(-(x)):(x))
#define N 202000
#define E 1001
#define L 1001
using std:: pair;
std:: priority_queue<pair <int, int> > heap;
int pre[N], nex[N], t[N];
bool vis[N];
inline int read() {
int x = 0, v = 1; char ch = getchar();
for(; ch<'0'||ch>'9'; v=(ch=='-')?(-1):(v),ch=getchar());
for(; ch<='9'&&ch>='0'; (x*=10)+=ch-'0',ch=getchar());
return x * v;
}
int main(void) {
int n = read();
int m = read();
rep(i, 1, n) {
t[i] = read();
pre[i] = i - 1;
nex[i] = i + 1;
pair <int, int> p(t[i], i);
heap.push(p);
}
pre[1] = n;
nex[n] = 1;
int ans = 0;
rep(i, 1, m) {
pair <int, int> top(heap.top());
heap.pop();
while (vis[top.second]) {
top = heap.top();
heap.pop();
if (heap.empty()) {
puts("Error!");
return 0;
}
}
ans += top.first;
t[top.second] = t[pre[top.second]] + t[nex[top.second]] - t[top.second];
vis[pre[top.second]] = vis[nex[top.second]] = 1;
nex[pre[pre[top.second]]] = top.second;
pre[top.second] = pre[pre[top.second]];
pre[nex[nex[top.second]]] = top.second;
nex[top.second] = nex[nex[top.second]];
heap.push(std:: make_pair(t[top.second], top.second));
}
printf("%d\n", ans);
return 0;
}

介绍了一种使用堆数据结构实现的特殊贪心算法,通过撤销机制确保每一步选择的最优性。该算法适用于解决特定类型的选择题问题,在选择过程中允许撤销之前的选择。
1万+

被折叠的 条评论
为什么被折叠?



