A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。
园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。
最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。
我们每次肯定是选美观值最大的位置种,然后考虑相邻的位置不能种的限制,可以考虑反悔贪心,假如我们选了(i)这个位置,设(i)左右两边的位置为(l_i,r_i),我们把(a_{r_i}+a_{l_i}-a_i)加进去,相当于把这三个合并成一个,这样下次如果选到这个就相当于选了(l_i,r_i)两个位置了。
这个过程可以用双向链表轻松实现。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define mp make_pair
#define fi first
#define se second
const int N = 5e5;
using namespace std;
int n,k,nxt[N + 5],pre[N + 5],vis[N + 5];
long long ans,a[N + 5];
priority_queue <pair<long long,int> > q;
int main()
{
scanf("%d%d",&n,&k);
if (k > n / 2)
{
cout<<"Error!"<<endl;
return 0;
}
for (int i = 1;i <= n;i++)
scanf("%lld",&a[i]);
for (int i = 1;i <= n;i++)
{
nxt[i] = i + 1;
pre[i] = i - 1;
q.push(mp(a[i],i));
}
pre[1] = n;
nxt[n] = 1;
for (int i = 1;i <= k;i++)
{
while (vis[q.top().se])
q.pop();
ans += q.top().fi;
int u = q.top().se;
q.pop();
a[u] = a[pre[u]] + a[nxt[u]] - a[u];
vis[pre[u]] = vis[nxt[u]] = 1;
nxt[pre[pre[u]]] = u;
pre[nxt[nxt[u]]] = u;
pre[u] = pre[pre[u]];
nxt[u] = nxt[nxt[u]];
q.push(mp(a[u],u));
}
cout<<ans<<endl;
return 0;
}