【反悔贪心】 种树

110 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

[国家集训队]种树

题目描述

A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。

园林部门得到指令后,初步规划出 nn 个种树的位置,顺时针编号 11nn。并且每个位置都有一个美观度 AiA_i,如果在这里种树就可以得到这 AiA_i 的美观度。但由于 AA 城市土壤肥力欠佳,两棵树决不能种在相邻的位置(ii 号位置和 i+1i+1 号位置叫相邻位置。值得注意的是 11 号和 nn 号也算相邻位置)。

最终市政府给园林部门提供了 mm 棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将 mm 棵树苗全部种上,给出无解信息。

输入格式

输入的第一行包含两个正整数 nnmm

第二行 nn 个整数,第 ii 个代表 AiA_i

输出格式

输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出 Error!

样例 #1

样例输入 #1

7 3
1 2 3 4 5 6 7

样例输出 #1

15

样例 #2

样例输入 #2

7 4
1 2 3 4 5 6 7

样例输出 #2

Error!

提示

数据编号nn 的大小数据编号nn 的大小
1130301111200200
223535121220072007
334040131320082008
444545141420092009
555050151520102010
665555161620112011
776060171720122012
8865651818199999199999
992002001919199999199999
10102002002020200000200000

对于全部数据:mnm\le n1000Ai1000-1000\le A_i\le1000

反悔贪心

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
# define M (200000+50)
using namespace std;
struct node{
    int value,place;
    friend bool operator < (node x,node y){
        return x.value < y.value;
    }
};
priority_queue<node> q;
int n,m,Ans,chose,nxt[M],pre[M],w[M],l,r;
bool vis[M];
void change(int x){
	vis[x]=1;
	nxt[pre[x]]=nxt[x];
	pre[nxt[x]]=pre[x];
	nxt[x]=0; pre[x]=0;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)  {
	  scanf("%d",&w[i]);
	}
	if((n>>1)<m){
    	cout<<"Error!"<<endl;
    	return 0;
	}
    for(int i=1;i<n;i++) nxt[i]=i+1; nxt[n]=1;
    for(int i=2;i<=n;i++) pre[i]=i-1; pre[1]=n;
    for(int i=1;i<=n;i++) q.push((node){w[i],i});
    for(int i=1;i<=m;i++){
    	while(vis[q.top().place]) q.pop() ;
    	node temp = q.top(); q.pop();
    	Ans+= temp.value;
    	l=pre[temp.place];   r=nxt[temp.place];
    	w[temp.place]=w[l]+w[r]-w[temp.place];
    	change(l);    change(r);
    	q.push((node){w[temp.place],temp.place});
	}
	printf("%d\n",Ans);
	return 0;
}