【Bzoj2151】種樹

題意

A城市有一個巨大的圓形廣場,爲了綠化環境和淨化空氣,市政府決定沿圓形廣場外圈種一圈樹。園林部門得到指令後,初步規劃出n個種樹的位置,順時針編號1到n。並且每個位置都有一個美觀度Ai,如果在這裏種樹就可以得到這Ai的美觀度。但由於A城市土壤肥力欠佳,兩棵樹決不能種在相鄰的位置(i號位置和i+1號位置叫相鄰位置。值得注意的是1號和n號也算相鄰位置!)。最終市政府給園林部門提供了m棵樹苗並要求全部種上,請你幫忙設計種樹方案使得美觀度總和最大。如果無法將m棵樹苗全部種上,給出無解信息。


解析

這題有一點特殊的就是不能種在相鄰位置,對於連續的i-1,i,i+1。我們要不就選i,要不就同時選i-1和i+1。然後我們可以建一個優先隊列,每次取完a[x]後,放入a[pre[x]] + a[nxt[x]] - a[x]。以後選到這個的話,就相當於取了旁邊兩個。也就是說把三個打包看做一個。具體刪點之類的用雙向鏈表實現。


#include <queue>
#include <cstdio>
#include <algorithm>

#define Rep( i , _begin , _end ) for(int i=(_begin);i<=(_end);i++)
#define For( i , _begin , _end ) for(int i=(_begin);i!=(_end);i++)

using std :: sort;
using std :: pair;
using std :: priority_queue;

const int maxx = 200000 + 25;

typedef pair<int,int> aii;

priority_queue< aii > quq;

int n,m,x,y,z,ans;
int pre[maxx],nxt[maxx],a[maxx];
bool vis[maxx];

void remove(int x){
    vis[x] = true;
    int l = pre[x],r = nxt[x];
    nxt[l] = r;pre[r] = l;
    pre[x] = nxt[x] = 0;
}

void Get(){
    while(vis[quq.top().second]) quq.pop();
    int x = quq.top().second;quq.pop();
    ans += a[x];a[x] = a[pre[x]] + a[nxt[x]] - a[x];
    remove(pre[x]);remove(nxt[x]);
    quq.push(aii(a[x],x));
}

int main(){
    scanf("%d%d",&n,&m);
    Rep( i , 1 , n ) scanf("%d",&a[i]);
    if(m > n/2) {puts("Error!");return 0;}
    Rep( i , 1 , n ) pre[i] = i-1,nxt[i] = i+1;
    nxt[n] = 1;pre[1] = n;
    Rep( i , 1 , n ) quq.push(aii(a[i],i));
    Rep( i , 1 , m ) Get();
    printf("%d",ans);
    return 0;
}
發佈了72 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章