P1484 種樹 - 堆 - 貪心
阿新 • • 發佈:2018-10-14
top val per ont include 都在 scan 就是 但是
但是還是有點難處理怎麽縮點,縮點之後應當刪除3個點,新建一個點,而原來其他位於這三個點左邊最靠右的點,若我們選了這個點,這說明這三個點就不可選了,也就是新點不可選,所以要把原來位於左邊最靠右的點的右邊連到新點上,這就需要開幾個數組模擬鏈表什麽的了
這題想得腦闊疼。。。我只想到可以選一個點,或者不選這個點選其左右兩個點的和
先來特殊情況,k=1, 然後k=2
可以發現由1到2的過程中,可以是一個本來被選的點,替換為他左右兩邊的點,收益增加了a[pos+1] + a[pos-1] - a[pos]
這個題是一個個選,直到選了k個,有種遞推的感覺,先確定種了前面幾個,再確定這一個該怎麽種
然後我不會處理若有別的點也選上,並且影響到這個pos+1和pos-1的情況
事實上可以把這三個點縮在一起啊(當然不能提前縮,要在pos這個點被選時縮起來)
然後我若再選一個別的點,若這個別的點會影響到pos+1或pos-1,因為縮了點,pos+1和pos-1現在都在pos上,所以這個“別的點”就會讓pos的值不可用,由於我們把值也縮在pos上了,直接導致這個pos替換為pos+1和pos-1不可用了,這也符合題意,並且更好寫
堆的題拆點(一個點拆成兩個,可以是等大的兩個,對左右兩邊起一個橋梁作用)和縮點(刪點)比較多
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; #define debug(x) cerr << #x << "=" << x << endl; const int MAXN = 1000000 + 10; typedef long long ll; ll n,k,a[MAXN],ans,flg[MAXN],cnt,l[MAXN],r[MAXN]; bool fina; struct node{ int val, pos; bool operator < (const node & a) const { return val < a.val; } }; priority_queue<node> q; int main() { scanf("%lld%lld", &n, &k); for(int i=1; i<=n; i++) { scanf("%lld", &a[i]); l[i] = i-1; r[i] = i+1; q.push((node){a[i], i}); } int tot = n; while(!q.empty()) { node now = q.top(); q.pop(); if(now.val <= 0) break; int pos = now.pos; if(flg[pos]) continue; if(++cnt > k) break; ans += now.val; a[++tot] = a[l[pos]] + a[r[pos]] - a[pos]; flg[pos] = flg[r[pos]] = flg[l[pos]] = 1; l[tot] = l[l[pos]], r[tot] = r[r[pos]]; r[l[tot]] = tot; l[r[tot]] = tot; q.push((node){a[tot], tot}); } printf("%lld", ans); return 0; }
P1484 種樹 - 堆 - 貪心