2151: 种树 不正经的贪心

2151: 种树

Time Limit: 10 Sec   Memory Limit: 259 MB
Submit: 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

【样例输入1】
7 3
1 2 3 4 5 6 7
【样例输入2】
7 4
1 2 3 4 5 6 7

Sample Output

【样例输出1】
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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值