[bzoj2288][pojChallenge]生日禮物
阿新 • • 發佈:2019-03-19
blog 個數 簡單的 ++ 題目 數據 最小 超過 abs
如果一開始正數區間個數就小於了m個,那麽就可以直接不用遍歷,反之我們需要去掉一些區間:
那麽如果選正數,就意味著不選這個數,也就是直接刪掉,因為後面還有更優的答案,tot-1。
如果選的是負數,說明左右區間合並,因為我們是絕對值較小,那麽對於我們答案的影響一定是最小的,那麽tot-1,合並區間。
否則那麽就tot+1。
合並區間的操作和數據備份是一樣的:https://www.cnblogs.com/chhokmah/p/10557925.html。
題目描述
ftiasch 18歲生日的時候,lqp18_31給她看了一個神奇的序列 A1, A2, …, AN. 她被允許選擇不超過 M 個連續的部分作為自己的生日禮物。
自然地,ftiasch想要知道選擇元素之和的最大值。你能幫助她嗎?
分析
這道題目還是非常簡單的,和數據備份幾乎是一樣的,吐槽完畢。
參照之前我們的思路,因為是m段不同的部分,那麽很明顯,一段全是同一符號的一定是一起被一起選走,那麽我們首先將原序列變換成只有正負交叉的序列,這樣保證了我們能夠一次就拿掉整個區間。
因為我們需要讓和最大,那麽有兩種情況:
- 正數區間
- 正數區間+負數區間+...
那麽我們思考一個貪心,如果一個正數區間非常的大,那麽我們一定會選擇這個區間,反之如果一個區間非常的小,也就是負數非常的大,那麽我們就一定不會選擇這個區間。從中顯然推出我們需要按照絕對值排序,排序過程用優先隊列來實現。
那麽如果選正數,就意味著不選這個數,也就是直接刪掉,因為後面還有更優的答案,tot-1。
如果選的是負數,說明左右區間合並,因為我們是絕對值較小,那麽對於我們答案的影響一定是最小的,那麽tot-1,合並區間。
否則那麽就tot+1。
合並區間的操作和數據備份是一樣的:https://www.cnblogs.com/chhokmah/p/10557925.html。
ac代碼
#include <bits/stdc++.h> #define ll long long #define ms(a, b) memset(a, b, sizeof(a)) #define inf 0x3f3f3f3f #define N 100005 using namespace std; template <typename T> inline void read(T &x) { x = 0; T fl = 1; char ch = 0; while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } x *= fl; } struct node { int id, val; node(int id, int val): id(id), val(val){} bool operator <(const node &rhs) const { return abs(val) > abs(rhs.val); } }; int a[N], b[N], lst[N], nxt[N]; priority_queue<node> q; int tot, n, m, ans; bool vis[N]; void remove(int x) { vis[x] = 1; lst[nxt[x]] = lst[x]; nxt[lst[x]] = nxt[x]; } int main() { memset(vis, 0, sizeof(vis)); read(n); read(m); for (int i = 1; i <= n; i ++) read(b[i]); tot = 1; for (int i = 1; i <= n; i ++) { if ((ll)a[tot] * b[i] >= 0) a[tot] += b[i]; else a[++ tot] = b[i]; } n = tot; tot = 0; for (int i = 1; i <= n; i ++) { if (a[i] > 0) tot ++, ans += 1ll * a[i]; } for (int i = 1; i <= n; i ++) { nxt[i] = i + 1; lst[i] = i - 1; q.push(node(i, a[i])); } while (tot > m) { tot --; while (vis[q.top().id]) q.pop(); int x = q.top().id; q.pop(); if (lst[x] != 0 && nxt[x] != n + 1) ans -= abs(a[x]); else if (a[x] > 0) ans -= a[x]; else { tot ++; continue; } a[x] = a[lst[x]] + a[nxt[x]] + a[x]; remove(nxt[x]); remove(lst[x]); q.push(node(x, a[x])); } printf("%d\n", ans); return 0; }
[bzoj2288][pojChallenge]生日禮物