洛谷P1792 [国家集训队]种树(链表 贪心)
题意
Sol
最直观的做法是wqs二分+dp。然而还有一种神仙贪心做法。
不难想到我们可以按权值从大到小依次贪心,把左右两边的打上标记,但这显然是错的比如\(1\ 231\ 233\ 232\)。我们会得到\(234\)而不是\(463\)。考虑加入一种反悔机制,也就是说我们可以增加一种决策来取消该决策的影响并加入新的决策的贡献。
考虑这样一种做法:把原来的点权改为\(231 + 232 - 233\),并用双向链表维护前驱后继。把\(233\)的前驱改为\(231\)的前驱并把\(233\)的后继改为\(232\)的后继。这样我们再次选择这个点的贡献的时候就相当于选了\(231 +232\)
复杂度\(O(nlogn)\)
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define Pair pair<int, int>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
#define LL long long
#define ull unsigned long long
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
using namespace std;
const int MAXN = 1e6 + 10, mod = 1e9 + 7, INF = 1e9 + 10;
const double eps = 1e-9;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline LL sqr(A x){return 1ll * x * x;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M, a[MAXN], pre[MAXN], nxt[MAXN], vis[MAXN], cnt;
priority_queue<Pair> q;
signed main() {
N = read(); M = read();
if(M > N / 2) {puts("Error!"); return 0;}
for(int i = 1; i <= N; i++) a[i] = read(), pre[i] = i - 1, nxt[i] = i + 1, q.push({a[i], i});
pre[1] = N; nxt[N] = 1;
int ans = 0;
while(M--) {
Pair p = q.top(); q.pop(); int c = p.se;
if( vis[c]) {M++; continue;}
ans += p.fi;
a[c] = a[pre[c]] + a[nxt[c]] - a[c]; vis[pre[c]] = 1; vis[nxt[c]] = 1;
pre[c] = pre[pre[c]]; nxt[c] = nxt[nxt[c]];
nxt[pre[c]] = c; pre[nxt[c]] = c;
q.push({a[c], c});
}
cout << ans;
return 0;
}
/*
2
1 1
*/
作者:自为风月马前卒
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。