2151: 种树
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 752 Solved: 409
[ Submit][ Status][ Discuss]
Description
A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。
Input
输入的第一行包含两个正整数n、m。第二行n个整数Ai。
Output
输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”,不包含引号。
Sample Input
7 3
1 2 3 4 5 6 7
【样例输入2】
7 4
1 2 3 4 5 6 7
Sample Output
15
【样例输出2】
Error!
题目大意:
如题。
思路:
假设我们选择了某个坑种树,那么相邻的坑就不可以在种树了,那么问题就来了,对于这样的一组样例
8 4
2 5 7 5 2 5 7 5
如果我们每次都选择最大的话,最后的选择是 7 7 2 但是我们可以选择更大的 5 5 7
这是因为如果某个坑的 价值 小于两边的坑价值的和,那么久相当于舍掉了某个更大的可能。但是贪心没有哦后悔的机会。。。
好尴尬。
所以这个题目还是不要用贪心了。。。
开个玩笑。。
那么我们怎样后悔呢?假设我们已经选择了第 x 个坑,那么就将 x 坑左边的坑和右边的坑都标记为不可选,x 坑的价值变为 左坑+右坑 - x 坑
那么下次如果我们再次选择 x 坑,就相当于我们选择了 x 坑左右的坑,而没有选择 x 坑。这样就实现了后悔。
最近几天在写 BZOJ 的题目。
好烦,题目都是不正经的题目。连一个贪心都不是正经贪心。看来还有很长的路要走啊。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int pre[200005];
int nextt[200005];
bool vis[200005];
struct node
{
int vv;
int pos;
friend bool operator < (const node &aa,const node &bb)
{
return aa.vv<bb.vv;
}
}a[200005],tt;
priority_queue<node>que;
void lala(int x)
{
vis[x]=1;
int ll=pre[x];
int rr=nextt[x];
nextt[ll]=rr;
pre[rr]=ll;
pre[x]=nextt[x]=0;
}
int ans;
void hehe()
{
while(vis[que.top().pos])
que.pop();
tt=que.top();
que.pop();
ans+=a[tt.pos].vv;
a[tt.pos].vv=a[pre[tt.pos]].vv+a[nextt[tt.pos]].vv-a[tt.pos].vv;
lala(pre[tt.pos]);
lala(nextt[tt.pos]);
tt.vv=a[tt.pos].vv;
que.push(tt);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].vv);
a[i].pos=i;
que.push(a[i]);
pre[i]=i-1;
nextt[i]=i+1;
}
if(m>n/2)
{
puts("Error!");
return 0;
}
pre[1]=n;
nextt[n]=1;
ans=0;
for(int i=0;i<m;i++)
{
hehe();
}
printf("%d\n",ans);
return 0;
}