【挖坑記】JZOJ 4726 種花

題目大意

圓形廣場共有 N 個種花的位置,順時針編號1到N。並且每個位置都有一個美觀度ai ,如果在這裏種花就可以得到這ai 的美觀度。兩株花不能種在相鄰的位置(1號和N號也算相鄰位置)。一共給了 M 株花,所以求如何擺這 M 株花美觀度最高。
n<=200000 , -1000<=ai<=1000
時間限制 1s
空間限制 256M

解題思路

貪心+堆
維護一個環形的鏈表和一個大根堆,每次去除堆頂元素k,設k的前驅和後繼分別爲pre和nex,把a[k]改成a[pre]+a[nex]-a[k],放回堆中,如此操作m次即可。

代碼如下,用模擬鏈表代替了鏈表

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 200006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll ding=2147483647;

struct nod
{
    int x,pre,nex;
} b[maxn];
struct node
{
    int x,y;
} d[maxn];
int i,j,n,m,tot,ans,a[maxn];
bool kan[maxn];
void ind(int x)
{
    d[++tot].x=x,d[tot].y=i;
    int t=tot;
    while (t>1 && d[t >> 1].x<d[t].x)
        swap(d[t >> 1],d[t]),t=t >> 1;
    return;
}
void down()
{
    int x=1,t=2;
    while (t<=tot && d[x].x<d[t].x || t+1<=tot && d[x].x<d[t+1].x)
    {
        if (t+1<=tot && d[t+1].x>d[t].x) t++;
        swap(d[x],d[t]);
        x=t,t=x*2;
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    if (m>n/2)
    {
        printf("Error!\n");
        return 0;
    }
    fr(i,1,n) scanf("%d",&a[i]),ind(a[i]);
    fr(i,1,n-1)
    {
        b[i].x=a[i];
        b[i].nex=i+1;
        b[i+1].pre=i;
    }
    b[1].pre=n,b[n].nex=1,b[n].x=a[n];
    fr(i,1,m)
    {
        while (kan[d[1].y]) d[1].x=-ding,down();
        ans+=d[1].x;
        int t=d[1].y;
        d[1].x=b[t].x=b[b[t].pre].x+b[b[t].nex].x-b[t].x;
        kan[b[t].pre]=kan[b[t].nex]=1;
        b[t].nex=b[b[t].nex].nex,b[b[t].nex].pre=t;
        b[t].pre=b[b[t].pre].pre,b[b[t].pre].nex=t;
        down();
    }
    printf("%d\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章