題目大意
圓形廣場共有 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;
}