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,&b)
#define sccc(a,b,c) scanf("%lld %lld %lld",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define schar(a) scanf("%c",&a)
#define pr(a) printf("%lld",a)
#define fo(i,a,b) for(int i=a;i<b;++i)
#define re(i,a,b) for(int i=a;i<=b;++i)
#define rfo(i,a,b) for(int i=a;i>b;--i)
#define rre(i,a,b) for(int i=a;i>=b;--i)
#define prn() printf("\n")
#define prs() printf(" ")
#define mkp make_pair
#define pii pair<int,int>
#define pub(a) push_back(a)
#define pob() pop_back()
#define puf(a) push_front(a)
#define pof() pop_front()
#define fst first
#define snd second
#define frt front()
#define bak back()
#define mem0(a) memset(a,0,sizeof(a))
#define memmx(a) memset(a,0x3f3f,sizeof(a))
#define memmn(a) memset(a,-0x3f3f,sizeof(a))
#define debug
#define db double
#define yyes cout<<"YES"<<endl;
#define nno cout<<"NO"<<endl;
using namespace std;
typedef vector<int> vei;
typedef vector<pii> vep;
typedef map<int,int> mpii;
typedef map<char,int> mpci;
typedef map<string,int> mpsi;
typedef deque<int> deqi;
typedef deque<char> deqc;
typedef priority_queue<int> mxpq;
typedef priority_queue<int,vector<int>,greater<int> > mnpq;
typedef priority_queue<pii> mxpqii;
typedef priority_queue<pii,vector<pii>,greater<pii> > mnpqii;
const int maxn=500005;
const int inf=0x3f3f3f3f3f3f3f3f;
const int MOD=100000007;
const db eps=1e-10;
int qpow(int a,int b){int tmp=a%MOD,ans=1;while(b){if(b&1){ans*=tmp,ans%=MOD;}tmp*=tmp,tmp%=MOD,b>>=1;}return ans;}
int lowbit(int x){return x&-x;}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int mmax(int a,int b,int c){return max(a,max(b,c));}
int mmin(int a,int b,int c){return min(a,min(b,c));}
void mod(int &a){a+=MOD;a%=MOD;}
bool chk(int now){}
int half(int l,int r){while(l<=r){int m=(l+r)/2;if(chk(m))r=m-1;else l=m+1;}return l;}
int ll(int p){return p<<1;}
int rr(int p){return p<<1|1;}
int mm(int l,int r){return (l+r)/2;}
int lg(int x){if(x==0) return 1;return (int)log2(x)+1;}
bool smleql(db a,db b){if(a<b||fabs(a-b)<=eps)return true;return false;}
bool bigeql(db a,db b){if(a>b||fabs(a-b)<=eps)return true;return false;}
bool eql(db a,db b){if(fabs(a-b)<eps) return 1;return 0;}
db len(db a,db b,db c,db d){return sqrt((a-c)*(a-c)+(b-d)*(b-d));}
bool isp(int x){if(x==1)return false;if(x==2)return true;for(int i=2;i*i<=x;++i)if(x%i==0)return false;return true;}
inline int read(){
    char ch=getchar();int s=0,w=1;
    while(ch<48||ch>57){if(ch==‘-‘)w=-1;ch=getchar();}
    while(ch>=48&&ch<=57){s=(s<<1)+(s<<3)+ch-48;ch=getchar();}
    return s*w;
}
inline void write(int x){
    if(x<0)putchar(‘-‘),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+48);
}
int gcd(int a, int b){
    if(a==0) return b;
    if(b==0) return a;
    if(!(a&1)&&!(b&1)) return gcd(a>>1,b>>1)<<1;
    else if(!(b&1)) return gcd(a,b>>1);
    else if(!(a&1)) return gcd(a>>1,b);
    else return gcd(abs(a-b),min(a,b));
}
int lcm(int x,int y){return x*y/gcd(x,y);}

int n,k;
struct node{
    int id,a;
    bool operator < (const node& o)const{return a<o.a;}
    node(int x,int y){id=x,a=y;}
};
priority_queue<node> q;
int l[maxn],r[maxn],a[maxn];
bool vis[maxn];

signed main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>k;
    re(i,1,n){
        cin>>a[i];
        q.push(node(i,a[i]));
        l[i]=i-1;
        r[i]=i+1;
    }
    l[n+1]=n,r[0]=1;
    int ans=0;
    while(k--){
        while(vis[q.top().id]) q.pop();
        node t=q.top();
        q.pop();
        if(t.a<0) break;
        ans+=t.a;
        int i=t.id;
        a[i]=a[l[i]]+a[r[i]]-a[i];
        t.a=a[i];
        vis[l[i]]=vis[r[i]]=1;
        l[i]=l[l[i]];
        r[i]=r[r[i]];
        r[l[i]]=i;
        l[r[i]]=i;
        q.push(t);
    }
    cout<<ans;
    return 0;
}

原文地址:https://www.cnblogs.com/oneman233/p/11566835.html

时间: 2024-10-08 20:44:59

P1484 种树(堆)的相关文章

P1484 种树 - 堆 - 贪心

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

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

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

种树 (堆模拟网络流)

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

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时,当然可能会有情况是选这两

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

可撤销贪心

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

题解小合集——第一弹

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

【bzoj2151】种树(堆/优先队列+双向链表)

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2151 这道题因为优先队列不怎么会用,而且手写堆的代码也不长,也想复习一下手写堆的写法……结果……WAWAWAWAW……看来我对堆的认识还是太浅薄了…… 这道题,如果没有限制不能选相邻的两个位置,那就肯定是贪心地选择m个美观度最大的位置种树.然而这里加了限制,那么我们可以注意到,如果一个美观度比较大的位置不被选上,一定是因为它两边的位置都被选了. 于是我们可以把n个美观度压进一个堆里,每

[堆] 种树

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