zoukankan      html  css  js  c++  java
  • LG1484 种树

    题意

    (N)个数,至多选(k)个,相邻两数不能同时选,问最大价值。

    思路

    一种假的思路:直接扔进对里面,每次都选最大的可以选的,再把两边和自己标记为不能选,一直贪心下去。是不是很有道理?
    假在哪里?虽然这个是最大的,旁边两个加起来比它大,就错了。
    把这个假贪心改一改,赐予它一个反悔的机会。如果它不选(i),那么它可以选则(last[i])(next[i]),这两个一定是一起选的(因为在一起才有超过(i)的可能)。此时它的价值为(a[last[i]]+a[next[i]]),原先已经选了(a[i]),所以就再扔一个(a[last[i]]+a[next[i]]-a[i]) 进去取代原来的数。由于这样选了(2)个数,而选一次反悔一次也恰好用掉(2)次机会,所以正好。
    置于维护(last、next)只要用双向链表就好了

    #include <bits/stdc++.h>
    using namespace std;
    pair<int,int> t;
    const int N=500005;
    int n,k,a[N],f[N],last[N],Next[N];
    long long ans;
    priority_queue <pair<int,int>> q;
    int main(){
    	scanf("%d%d",&n,&k);
    	for (int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		q.push(make_pair(a[i],i));
    	}
    	for (int i=1;i<=n;i++) last[i]=i-1,Next[i]=i+1;
    	last[n+1]=n,Next[0]=1;
    	for (int i=1;i<=k;i++){
    		t=q.top();
    		while (f[t.second]) q.pop(),t=q.top();
    		q.pop();
    		if (t.first<0) break;
    		ans+=t.first;
    		int id=t.second;
    		f[last[id]]=f[Next[id]]=1;
    		a[id]=a[last[id]]+a[Next[id]]-a[id];
    		q.push(make_pair(a[id],id));
    		last[id]=last[last[id]],Next[id]=Next[Next[id]];
    		Next[last[id]]=id,last[Next[id]]=id;
    	}
    	printf("%lld",ans);
    }
    
    * 生而自由 爱而无畏 *
  • 相关阅读:
    技术选型总结
    这些年来收集的好用的好玩的软件,强烈推荐给大家
    如何解决markdown中图片上传的问题
    01.如何把.py文件打包成为exe,重点讲解pyinstaller的用法
    Asp.net中汉字转换成为拼音
    程序员常用网址收集
    通过IP来判断所在城市
    以太坊
    分布式系统领域经典论文翻译集
    T50
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/10632781.html
Copyright © 2011-2022 走看看