• [P1484] 种树


    Link:https://www.luogu.org/problemnew/show/P1484

    Brief Introduction:在一个长为N上的序列取至多K个数,要保证所取的数两两不相邻,求Max(所取的数的和)。

                                   N<=5e5,K<=N/2

    Algorithm:

    1、首先O(NK)的dp是能立刻想到的 dp[n][k]=max(dp[n-1][k],dp[n-2][k-1]+value[n]) 

          可以使用滚动数组优化

          但明显不足以解决N<=5e5的问题

    2、可以从最简单的问题开始考虑,如果K=1,那么取最大值。设该点的位置为P。

          当问题扩大时,棘手的问题在于不易维护所取数两两不相邻这一条件

          为了每次选取最大值时可以忽略这个条件,我们选择P后将P-1,P,P+1合并,看为同一个点,这样保证接下来可以任意选点

          为了提供“反悔”这个选项,新点的权值设为value(P-1)+value(P+1)-value(P),如选择新点则表示“反悔”不选P,而改选P-1和P+1.

          维护数列中插入、删除、求最大值,可以想到使用堆/Priority_queue维护

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        char ch;int f=0,num;
        while(!isdigit(ch=getchar())) f|=(ch=='-');
        num=ch-'0';
        while(isdigit(ch=getchar())) num=num*10+ch-'0';
        return f?-num:num;
    }
    
    #define F first
    #define S second
    
    const int MAXN=5e5+10;
    typedef pair<int,int> P;
    typedef long long ll;
    priority_queue<P> Q;
    bool vis[MAXN];
    ll l[MAXN],r[MAXN],dat[MAXN];
    
    int main()
    {
        int n=read(),k=read();
        for(int i=1;i<=n;i++) 
        {
            dat[i]=read();
            l[i]=i-1;r[i]=i+1;  //维护每个点的两边的点的坐标
            Q.push(P(dat[i],i));
        }
        
        ll res=0;l[0]=1;r[n+1]=n; //对边界设置
        for(int i=1;i<=k;i++)
        {
            while(vis[Q.top().S]) Q.pop(); //如已被合并,则不处理
            P t=Q.top();Q.pop();
            if(t.F<0) break;
            res+=t.F;vis[l[t.S]]=vis[r[t.S]]=true;
            
            dat[t.S]=t.F=dat[l[t.S]]+dat[r[t.S]]-dat[t.S];
            Q.push(t);
            
            r[t.S]=r[r[t.S]];l[t.S]=l[l[t.S]];  //不真正合并,仅维护左右点坐标
            l[r[t.S]]=t.S;r[l[t.S]]=t.S;
        }
        cout << res;
        return 0;
    }

    Review:

    1、当遇到常见问题被加以特殊条件时,注意化归,通过转化将问题变为易解问题

       能否忽略特殊条件解题

    2、在决策类问题中,我们可以利用贪心+“反悔”选项的方式解决问题

         将权值变为 其他解-当前贪心解

    3、有时在维护合并操作时,不一定要真正合并。

          可将信息集中在其中一点上,只维护每个点相邻点坐标即可。

          同时,要对“废点”打上标记,之后对其不再处理

  • 相关阅读:
    Elementary Methods in Number Theory Exercise 1.2.25
    Elementary Methods in Number Theory Exercise 1.2.14
    图解欧几里德算法
    图解欧几里德算法
    Elementary Methods in Number Theory Exercise 1.2.14
    Android中的长度单位详解(dp、sp、px、in、pt、mm)
    分享下多年积累的对JAVA程序员成长之路的总结
    android异常之都是deamon惹的祸The connection to adb is down, and a severe error has occured.
    TomatoCartv1.1.8.2部署时报错
    JavaScript浏览器对象之二Document对象
  • 原文地址:https://www.cnblogs.com/newera/p/8977924.html
Copyright © 2020-2023  润新知