[P1484] Planting trees

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

 

Brief Introduction: Take at most K numbers in a sequence of length N. To ensure that the numbers taken are not adjacent to each other, find Max (the sum of the numbers taken).

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

 

Algorithm:

1. First of all, the dp of O(NK) is immediately thought of dp[n][k]=max(dp[n-1][k],dp[n-2][k-1]+value[n] ) 

      Can be optimized using rolling arrays

      But it is obviously not enough to solve the problem of N<=5e5

 

2. You can start from the simplest problem. If K=1, then take the maximum value. Let the location of this point be P.

      When the problem expands, the tricky problem is that it is not easy to maintain the condition that the numbers taken are not adjacent to each other

      In order to ignore this condition every time we select the maximum value , we select P and combine P-1, P, and P+1 as the same point, which ensures that any point can be selected next .

      In order to provide the option of "repentance" , the weight of the new point is set to value(P-1)+value(P+1)-value(P). If a new point is selected, it means that "returning" does not select P, but selects P instead. -1 and P+1 .

 

      To maintain insertion, deletion, and maximum value in the array, you can think of using heap/Priority_queue maintenance

 

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];

intmain ()
{
    int n=read(),k=read();
    for(int i=1;i<=n;i++) 
    {
        dat[i]=read();
        l[i] =i- 1 ;r[i]=i+ 1 ; //Maintain the coordinates of the points on both sides of each point
        Q.push(P(dat[i],i));
    }
    
    ll res = 0 ;l[ 0 ]= 1 ;r[n+ 1 ]= n; //set for boundary
     for ( int i= 1 ;i<=k;i++ )
    {
        while (vis[Q.top().S]) Q.pop(); //If it has been merged, it will not be processed
        P t=Q.top();Q.pop();
        if(t.F<0) break;
        res+=t.F;vis[l[t.S]]=vis[r[t.S]]=true;
        
        dat [tS] = tF = dat [l [tS]] + dat [r [tS]] - dat [tS];
        Q.push(t);
        
        r[tS] =r[r[tS]];l[tS]= l[l[tS]]; //Not really merged, only the left and right point coordinates are maintained
        l[r[t.S]]=t.S;r[l[t.S]]=t.S;
    }
    cout << res;
    return 0;
}

 

 

Review:

1. When encountering common problems that are subject to special conditions, pay attention to transformation, and transform the problem into an easy-to-solve problem

   Can I ignore special conditions to solve problems?

 

2. In decision-making problems, we can use the greed + "repentance" option to solve the problem

     Change the weights to other solutions - the current greedy solution

 

3. Sometimes when maintaining a merge operation, it is not necessary to actually merge.

      The information can be concentrated on one of the points, and only the coordinates of the adjacent points of each point can be maintained.

      At the same time, mark the "waste points" and do not deal with them after that .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325117820&siteId=291194637