【BZOJ 2288】 生日礼物
【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=2288
【算法】
先将这个序列的正负数合并起来,变成一个正负交替的序列
如果新序列的正数个数小于等于M,那么直接输出正数的和即可
否则,我们可以将某些正数和负数合并起来,或者不要某些正数
将所有数按绝对值排序,放入堆中,问题就转化为了 : 在这些数中选出(Cnt - M)个数(其中Cnt为正数的个数),
选了一个数后相邻的两个数就不能选,使得最后的和尽可能小
这个问题可以用CTSC2007数据备份的方法来解决,详见 : https://www.cnblogs.com/evenbao/p/9252503.html
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 10; const int INF = 2e9; struct info { int d,pos; }; int i,n,m,l,r,cnt,ans,len; int a[MAXN],b[MAXN],val[MAXN],pre[MAXN],nxt[MAXN]; bool visited[MAXN]; info tmp; class Heap { private : int tot; info hp[MAXN]; public : inline bool cmp(info a,info b) { return a.d < b.d; } inline void Up(int x) { if (x == 1) return; int fa = x >> 1; if (cmp(hp[x],hp[fa])) { swap(hp[x],hp[fa]); Up(fa); } } inline void Down(int x) { int son = x << 1; if (son > tot) return; if ((son + 1 <= tot) && cmp(hp[son+1],hp[son])) son++; if (cmp(hp[son],hp[x])) { swap(hp[son],hp[x]); Down(son); } } inline void insert(info x) { tot++; hp[tot] = x; Up(tot); } inline void del() { swap(hp[1],hp[tot]); tot--; Down(1); } inline info get() { return hp[1]; } } H; int main() { scanf("%d%d",&n,&m); for (i = 1; i <= n; i++) scanf("%d",&a[i]); while (n && a[n] <= 0) n--; i = 1; while (i <= n && a[i] <= 0) i++; if (i > n) { printf("%d\n",0); return 0; } for (; i <= n; i++) { if ((a[i] > 0 && a[i-1] > 0) || (a[i] <= 0 && a[i-1] <= 0)) b[len] += a[i]; else b[++len] = a[i]; } for (i = 1; i <= len; i++) { if (b[i] > 0) { ans += b[i]; cnt++; } else b[i] = -b[i]; } if (cnt <= m) { printf("%d\n",ans); return 0; } for (i = 1; i <= len; i++) { pre[i] = i - 1; nxt[i] = i + 1; H.insert((info){b[i],i}); } b[0] = b[len+1] = INF; for (i = m; i < cnt; i++) { tmp = H.get(); while (visited[tmp.pos]) { H.del(); tmp = H.get(); } ans -= tmp.d; H.del(); visited[pre[tmp.pos]] = true; visited[nxt[tmp.pos]] = true; b[tmp.pos] = b[pre[tmp.pos]] + b[nxt[tmp.pos]] - tmp.d; nxt[pre[pre[tmp.pos]]] = tmp.pos; pre[tmp.pos] = pre[pre[tmp.pos]]; pre[nxt[nxt[tmp.pos]]] = tmp.pos; nxt[tmp.pos] = nxt[nxt[tmp.pos]]; H.insert((info){b[tmp.pos],tmp.pos}); } printf("%d\n",ans); return 0; }