1. 程式人生 > >JZOJ5372. 【NOIP2017提高A組模擬9.17】貓 連結串列+貪心+堆優化

JZOJ5372. 【NOIP2017提高A組模擬9.17】貓 連結串列+貪心+堆優化

題意:一個長度為n的環,每個點有貢獻,取了一個就不能取他的相鄰,問取1-n/2個的最優方案是多少。
DP可能會掛,我自己試了試好像會出點問題= =畢竟是環,如果類似這種問題,不能拆環一般就不要DP
於是考慮貪心,大根堆優化。其實這題可以算是堆優化貪心的典型例題了,每次取完堆頂以後把這個點的貢獻改為這個點相鄰的兩個點的貢獻-這個點的貢獻,然後把相鄰兩個刪掉,相當於再次取到這個點時就是撤銷,就是把這個點去掉,然後選擇相鄰的兩個點的貢獻。因為涉及到動態刪除,所以用連結串列維護。
注意開ll,被坑了QAQ。
luogu好像有一道差不多的題目,叫什麼編譯優化,就是沒要求輸出n/2次,所以那題水一點。。

#include<bits/stdc++.h>
using namespace std;
#define N 200010
#define LL long long
#define P make_pair
int n,t,l[N],r[N];
bool vis[N];
LL ans,a[N];
priority_queue< pair<LL,int> >q;
int input() {
    int f=1,g=0; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    while
(c>='0'&&c<='9') {g=g*10+c-'0';c=getchar();} return f*g; } int main() { freopen("cat.in","r",stdin); freopen("cat.out","w",stdout); n=input(); for(int i=1;i<=n;i++) a[i]=input(),q.push(P(a[i],i)); for(int i=1;i<=n;i++) l[i]=i-1,r[i]=i+1; l[1]=n,r[n]=1; for
(int i=1;i<=n/2;i++) { while(vis[t=q.top().second]) q.pop(); ans+=q.top().first,q.pop(); vis[l[t]]=vis[r[t]]=1,a[t]=a[l[t]]+a[r[t]]-a[t]; l[t]=l[l[t]],r[t]=r[r[t]],r[l[t]]=l[r[t]]=t; q.push(P(a[t],t)),printf("%lld\n",ans); } return 0; }