Luogu P1484 种树

这道题目还是比较简单的

首先题目的意思就让我们很轻易地想到DP

我们设f[i][j]表示前i个坑中种j棵树的最大利益,则有:

f[i][j]=max(f[i-1][j],f[i-2][j-1]+a[i])

然而对于本题的数据范围之能得50pts

要A掉的话还是要动一些脑子的

我们先从小的情况开始讨论:

  • 当k=1时,我们只需要找一个最大的收益即可(当然全负就不要找了)
  • 当k=2时,我们先挑选一个最大的,若接下来最大的不是这个数两侧的数,那就区接下来最大的数即可
  • 当k=2时,当然可能会有情况是选这两个数相邻的两个数(当然也只有这种情况)。表述得清楚一些就是若第一次选了a[i],除非最优解是a[i-1]+a[i+1],否则都是上面的选法最优

以此我们发现对于已经被选择的a[i],a[i-1],a[i+1]要么同时被选,要么同时落选

因此我们开一个大根堆,每次取出a[i]之后把它的值累加至ans后,将a[i]的值改成a[pre[i]]+a[nxt[i]]-a[i] (这里的pre[i]表示i的前驱,nxt[i]表示i的后继,刚开始就分别是i-1,i+1)

为什么呢,因为我们想一下,这样就给了程序一个返回的机会,此时当你选择了新的a[i]时,其实就是选择了原来的a[pre[i]]和a[nxt[i]]

然后开一个STL堆即可水过

CODE

#include<cstdio>
#include<queue>
using namespace std;
const int N=500005;
struct node
{
    int v,num;
    bool operator <(const node &s) const
    {
        return s.v>v;
    }
};
priority_queue <node> big;
int a[N],pre[N],nxt[N],n,k,tot;
bool vis[N];
long long ans;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch=tc(); int flag=1;
    while (ch<‘0‘||ch>‘9‘) { if (ch==‘-‘) flag=-1; ch=tc(); }
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=tc();
    x*=flag;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i;
    read(n); read(k);
    for (i=1;i<=n;++i)
    read(a[i]),pre[i]=i-1,nxt[i]=i+1,big.push((node){a[i],i});
    nxt[0]=1; pre[n+1]=n;
    while (tot<k)
    {
        while (vis[big.top().num]) big.pop();
        node p=big.top(); big.pop();
        if (p.v<0) break; ++tot; ans+=p.v;
        p.v=a[p.num]=a[pre[p.num]]+a[nxt[p.num]]-a[p.num];
        vis[pre[p.num]]=vis[nxt[p.num]]=1;
        pre[p.num]=pre[pre[p.num]]; nxt[pre[p.num]]=p.num;
        nxt[p.num]=nxt[nxt[p.num]]; pre[nxt[p.num]]=p.num;
        big.push(p);
    }
    printf("%lld",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/cjjsb/p/9026156.html

时间: 2024-10-08 20:46:55

Luogu P1484 种树的相关文章

【洛谷】【堆+贪心】P1484 种树

[题目描述:] cyrcyr今天在种树,他在一条直线上挖了n个坑.这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树.而且由于cyrcyr的树种不够,他至多会种k棵树.假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利. [输入格式:] 第一行,两个正整数n,k. 第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利. [输出格式:] 输出1个数,表示cyrcyr种树的最大获利. 输

P1484 种树(堆)

堆优化的贪心,考虑种一棵树的最大收益,种了当前树两旁的树之后的收益为a[i-1]+a[i+1]-a[i] 用双向链表维护住左右关系,大根堆则可以“反悔”,维护另一个记录某个坑能不能种树的数组即可 代码: #include <bits/stdc++.h> #define int long long #define sc(a) scanf("%lld",&a) #define scc(a,b) scanf("%lld %lld",&a,&am

P1484 种树

dalao #include<cstdio> #include<iostream> #include<queue> #include<algorithm> using namespace std; struct node { int pos; long long val; bool operator < (const node &b) const { return val<b.val; } }; priority_queue<nod

P1484 种树 - 堆 - 贪心

这题想得脑阔疼...我只想到可以选一个点,或者不选这个点选其左右两个点的和 先来特殊情况,k=1, 然后k=2 可以发现由1到2的过程中,可以是一个本来被选的点,替换为他左右两边的点,收益增加了a[pos+1] + a[pos-1] - a[pos] 这个题是一个个选,直到选了k个,有种递推的感觉,先确定种了前面几个,再确定这一个该怎么种 然后我不会处理若有别的点也选上,并且影响到这个pos+1和pos-1的情况 事实上可以把这三个点缩在一起啊(当然不能提前缩,要在pos这个点被选时缩起来) 然

可撤销贪心

1. CF 867E Buy Low Sell High 大意: 第$i$天可以花$a_i$元买入或卖出一股或者什么也不干, 初始没钱, 求$n$天后最大收益. 用堆维护最小值, 假设当前考虑的值为$a_i$, 堆中最小值为$t$, 则卖出贡献$a_i-t$, 若贡献$>0$直接加上, 然后再填进去一个$a_i$, 之后若有更优值$x$, 总贡献会变为$x-a_i+a_i-t$, 也就相当于进行反悔操作. #include <iostream> #include <cstdio&g

差分拘束介绍、总结与例题

差分约束的具体概念: 如果一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj≤k的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统. 例子: 假设有3个数a,b,c 我们知道: a-b>=2 b-c>=3 a-c>=3 那么:a与c的差值最小为多少? a比b至少大2,b比c至少大3,那a比c就至少大5. 这很容易理解. 但是如果不等式很多呢? 100个数?1000个数?10000个数-- 我们从一开始的例子开始考虑. 我们把这想象成一个图.每个不等式就是一条有向边.

题解小合集——第一弹

(转载于我的洛谷博客) 索引: 第一题:P2552 团体操队形 第二题:P3146 248 第三题:P3147 262144 第四题:P1972 花花的项链 第五题:P1484 种树 第六题:P5132 Cozy Glow之拯救小马国 第七题:P1198 最大数 第八题:P2023 维护序列 第九题:P1967 货车运输 第十题:P1313 计算系数 第一题:P2552 团体操队形 题解思路:大模拟,仔细点就好 这道题以一个点需要注意--就是梅花桩队形的奇数排列和偶数排列的规律是略有不同的 奇数

luogu P3799 妖梦拼木棒

二次联通门 : luogu P3799 妖梦拼木棒 /* luogu P3799 妖梦拼木棒 用一个桶存下所有的木棒 美剧两根短的木棒长度 后随便乘一乘就 好了.. */ #include <algorithm> #include <cstdio> #define Mod 1000000007 #define Max 5000 void read (int &now) { now = 0; register char word = getchar (); while (wo

[luogu P1967][NOIp2013]P1967 货车运输

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z