1. 程式人生 > >BZOJ 2288: 【POJ Challenge】生日禮物 優先隊列+貪心+鏈表

BZOJ 2288: 【POJ Challenge】生日禮物 優先隊列+貪心+鏈表

else 端點 () empty 隊列 view 否則 pan 正則

這題看別人題解的

這題說可以轉換成數據備份。
這題可以把一段同號的數並成一個數,那麽就變成了一個正負交替的序列,然後把頭尾的負數去掉。
然後就是把所有的正值都加起來,並統計正數的段數cnt,如cnt<=m,那麽這些整數的和就是答案

如果cnt>m,那我們就要不斷地去掉一段,直到cnt=m

先把所有數的絕對值加進優先隊列,每次去一個最小的出來然後減掉,最後的即為答案。
為什麽是正確的呢?因為如果減去的值在原數列中為正則相當於不要這個數,否則就相當於選了這個負數然後把兩邊的正值合並起來。

無論減去正數還是負數,都要保證每次操作能夠使段數cnt-1,這是我們的目的所在

既如果去掉的是正數,保證了cnt-1,如果去掉了負數,那麽要保證它的兩邊必須要是正數,這樣才能使旁邊兩個正數加上這個負數,使得我們原來取的它的旁邊的兩段正數加上這個負數後,段數減一,所以處於左右端點的負數都要先去掉
但有一個問題,就是若選了一個數那麽其兩邊的數就必定不能被選,那麽就轉換成了數據備份了。

真的是被這題搞得快自閉了,自己寫的一直wa,經過不斷修改代碼,兩個代碼來回交,大概交了40次,才發現我哪裏錯了

錯的
l[pos] = l[l[pos]]; r[pos] = r[r[pos]]; r[l[l[pos]]] = pos; l[r[r[pos]]] = pos;

這個是導致我WA了20次的原因,怎麽也沒想到是這個地方錯了,我還在瘋狂修改其他地方。

對的
r[l[l[pos]]] = pos;
l[r[r[pos]]] = pos;
l[pos] = l[l[pos]];
r[pos] = r[r[pos]];

原來錯的那個我的 l[pos] 已經先更改過了。

技術分享圖片
#include<bits/stdc++.h>
using
namespace std; typedef unsigned long long ull; const int maxn = 1e5 + 5; int a[maxn], l[maxn], r[maxn],n,m,ans,cnt; bool vis[maxn]; struct data { int val, pos; data(int val1 = 0, int pos1 = 0) { val = val1; pos = pos1; } bool operator < (const data &a) const { return a.val<val; } }; priority_queue
<data> que; int main() { cin >> n >> m; int tot = 1; for (int i = 1; i <= n; i++) { int tmp; cin >> tmp; if (a[tot] * tmp >= 0) a[tot] += tmp; else a[++tot] = tmp; } int left = 1; if (a[1]<0) left++; if (a[tot]<0) tot--; for (int i = left; i <= tot; i++) { if (a[i] > 0) cnt++, ans += a[i]; a[i] = abs(a[i]); que.push(data(a[i],i)); //que.push(data(a[i],i)); l[i] = i - 1; r[i] = i + 1; } l[left]=r[tot] = 0; if (cnt <= m) cout << ans << endl; else { int num = cnt - m; for (int i = 1; i <= num;i++) { while (vis[que.top().pos] && !que.empty()) que.pop(); int pos = que.top().pos; que.pop(); ans -= a[pos]; if (!l[pos]) { vis[pos] = vis[r[pos]] = true; l[r[r[pos]]] = 0; } else if (!r[pos]) { vis[pos] = vis[l[pos]]=true; r[l[l[pos]]] = 0; } else { vis[l[pos]] = vis[r[pos]] = true; a[pos] = a[l[pos]] + a[r[pos]] - a[pos]; que.push(data(a[pos],pos)); r[l[l[pos]]] = pos; l[r[r[pos]]] = pos; l[pos] = l[l[pos]]; r[pos] = r[r[pos]]; } } cout << ans << endl; } return 0; }
View Code

BZOJ 2288: 【POJ Challenge】生日禮物 優先隊列+貪心+鏈表