【挖坑记】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
#include
#include
#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.x)
        swap(d[t >> 1],d[t]),t=t >> 1;
    return;
}
void down()
{
    int x=1,t=2;
    while (t<=tot && d[x].x.x || t+1<=tot && d[x].x1].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;
}

你可能感兴趣的:(挖坑记,贪心,堆)