BZOJ 2151 种树 贪心+优先队列+HASH

题意:链接

方法:贪心+优先队列

解析:

首先裸上贪最大的肯定不对。

DP可行么?可行,两个数组一个记录选一个记录不选好像差不多n^2?

不过还是想想贪心。

贪最大的为什么不对?

因为有可能它旁边的两个加起来比它更优越?

所以能否找到一点关系呢?

既然话都说到这了,两个加起来可能更优越。

所以我们在选了最大的之后是否应该回推一个值呢?代表选旁边俩。

我们发现选旁边俩是两个单位,选一个是一个单位,如果我们推回去某个值后这个值相当于对应删去一个单位选两个单位,即增加一个单位,这显然不会影响最终我们选几个单位。

那么这个值是啥呢?

a[i+1]+a[i-1]-a[i]

很显然吧,所以我们只需要每次删掉三个东西推进去一个即可。

不影响我们选的东西的数量。

那么复杂度呢?

我们可以搞一个优先队列,然后hash标记某个点是否已删。

然后开两个数组记录某个值前面的点以及后面的点。

代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 200010
using namespace std;
int n,m;
int a[N];
int be[N];
int af[N];
int hash[N];
struct node
{
    int no;
    int val;
}tmp[N];
int tot;
priority_queue <node>q;
bool operator < (node s,node t)
{
    return s.val<t.val;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        if(i==1)be[i]=n;
        else be[i]=i-1;
        if(i==n)af[i]=1;
        else af[i]=i+1;
        scanf("%d",&a[i]);
        node tmp;
        tmp.no=i,tmp.val=a[i];
        q.push(tmp);
    }
    if(m>(n/2)){puts("Error!");return 0;}
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        node u=q.top();
        q.pop();
        while(hash[u.no])
        {
            u=q.top();
            q.pop();
        }
        ans+=u.val;
        int bex=be[u.no],afx=af[u.no];
        hash[bex]=hash[afx]=1;
        tot=0;
        u.val=a[u.no]=a[bex]+a[afx]-a[u.no];
        af[u.no]=af[afx],be[u.no]=be[bex];
        be[af[afx]]=u.no,af[be[bex]]=u.no;
        q.push(u);
    }
    printf("%d\n",ans);
} 

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-24 15:09:47

BZOJ 2151 种树 贪心+优先队列+HASH的相关文章

bzoj 2151: 种树【贪心+堆】

和数据备份差不多 设二元组(i,a[i]),开一个大根堆把二元组塞进去,以len排序,每次取出一个二元组 因为单纯的贪心是不行的,所以设计一个"反悔"操作. 记录二元组的前驱pr后继ne,把拿出来的二元组的len加进答案,然后把当前二元组和它的前驱后继当成一个,也就是len[x]=a[pr[x]]+a[ne[x]]-a[x],相应修改前驱后继,然后"删掉"前驱后继的二元组,这样的意思是如果再次选了修改过的二元组x,就意味着退还掉x,选择它的前驱后继,易证这样个数和a

BZOJ 2151 种树

贪心+priority_queue. #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 200050 using namespace std; long long n,val[maxn],ans=0,m; bool vis[maxn]; struct node { long long w,pos; friend bool operator &l

【BZOJ 2151】 2151: 种树 (贪心+堆)

2151: 种树 Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度.但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置.值得注意的是1号和n号也算相邻位置!).最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大.如果无法将m棵树苗

【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列)

1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅

种树(贪心)

2151: 种树 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 714  Solved: 397[Submit][Status][Discuss] Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度.但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i

poj3190Stall Reservations(贪心+优先队列)

题目链接: 啊哈哈,点我点我 思路: 首先根据挤奶时间的先后顺序排序...然后将第一头牛加入优先队列..然后就是加入优先队列的牛应该根据越早结束挤奶那么优先级更高,如果时间结束点相等,那么开始时间早的优先级高... 然后从前向后枚举.如果碰到有牛的挤奶时间的开始值大于优先队列的首部的结束值,那么说明这两头牛可以一起公用一个挤奶房..然后从优先队列中删除这头牛..那么这个问题就得到解决了... 题目: Language: Default Stall Reservations Time Limit:

poj 2431 Expedition (贪心+优先队列)

Expedition Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6890   Accepted: 2065 Description A group of cows grabbed a truck and ventured on an expedition deep into the jungle. Being rather poor drivers, the cows unfortunately managed to

BZOJ 2761 不重复数字 (Hash)

题解:直接使用STL中的hash去重即可 #include <cstdio> #include <map> using namespace std; int ans[50010]; int main(){ int T,n,tmp; scanf("%d",&T); while(T--){ int cnt=0; map<int,int>m; scanf("%d",&n); for(int i=0;i<n;i++)

POJ1456Supermarket(贪心+优先队列)

Supermarket Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9103   Accepted: 3891 Description A supermarket has a set Prod of products on sale. It earns a profit px for each product x∈Prod sold by a deadline dx that is measured as an int