BZOJ 2151 种树

82 篇文章 0 订阅
6 篇文章 0 订阅

Problem

BZOJ

Solution

kaisa158题解 Orz

贪心,只不过贪心有后效性,所以引入反悔机制解决后效性。

按照贪心,每次会选取权值最大的地方种树,如这组数据:
4 2
3 5 4 1
那么,贪心算法首先将选取5,而在做第二个选择是1,反而不一定是最优答案,因为之前做的选择会影响到后来的选择,即我们常说的后效性。

我们考虑起前面的选择只会对两侧的选择造成影响,也就是说,选取2号之后,1号和3号可能才应该更优,即v[1]+v[3]>v[2]+v[4],不妨模拟一下:

第一步贪心后ans=v[2],在删去1号和3号之后,加入新的权值v[1]+v[3]-v[2],那么当继续选择时,如果v[1]+v[3]-v[2]>v[4],也就是说v[1]+v[3]>v[2]+v[4],那么我们就选择v[1]+v[3]-v[2]加入答案。

这种处理贪心后效性的思想应该还可以扩展,很神奇的说。

Code

#include <algorithm>
#include <cstdio>
#define rg register
#define mk(x,y) make_pair(x,y)
using namespace std;
typedef pair<int,int> pii;
const int maxn=200010;
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
struct Heap{
    int p;pii a[maxn];
    void push(pii x){a[++p]=x;push_heap(a+1,a+p+1);}
    void pop(){pop_heap(a+1,a+p+1);p--;}
}h;
int n,m,ans,a[maxn],vis[maxn],pre[maxn],nxt[maxn];
void erase(int x)
{
    vis[x]=1;
    nxt[pre[x]]=nxt[x];pre[nxt[x]]=pre[x];
    nxt[x]=pre[x]=0;
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    read(n);read(m);
    if(n<m+m){puts("Error!");return 0;}
    for(rg int i=1;i<=n;i++)read(a[i]),pre[i]=i-1,nxt[i]=i+1,h.push(mk(a[i],i));
    pre[1]=n;nxt[n]=1;
    while(m)
    {
        int x=h.a[1].second;
        if(vis[x]){h.pop();continue;}
        ans+=h.a[1].first;h.pop();
        a[x]=a[pre[x]]+a[nxt[x]]-a[x];
        erase(pre[x]);erase(nxt[x]);
        h.push(mk(a[x],x));m--;
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值