• 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;
    }
    
  • 相关阅读:
    linux命令(48):nl命令
    linux命令(47):rmdir命令
    linux命令(46):chgrp命令
    linux命令(45):diff命令
    linux命令(44):date命令
    linux命令(43):cal命令
    linux命令(42):wc命令
    linux命令(41):watch命令
    linux命令(40):at命令
    linux下禁止root远程登录
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9026156.html
Copyright © 2020-2023  润新知