[poj3017] Cut the Sequence - Monotonic queue optimization DP

Topic meaning:

Given a sequence of length n and an integer m, find a partition such that the sum of each segment is no greater than m and the sum of the maximum values ​​of each segment is minimal.

Ideas:

Let dp[i] be the minimum sum of the first i, the equation is obvious:

d p [ i ] = m i n ( d p [ j ] + max ( a [ j + 1 ] . . . a [ i ] ) )

Naive time complexity O ( n 2 )
Considering how to find the maximum value of a continuous interval, it is found that a monotonically decreasing queue can be used for maintenance, but this still cannot optimize the time. It is found that the dp array also satisfies the monotonic increase, so for the interval corresponding to each element in the monotonically decreasing queue, the minimum value of its dp must be taken at the front end of the interval, so that each element in the monotonic queue is Corresponds to a unique dp value. Since this is a monotonic queue, each element will only be enqueued once and dequeued once, so just maintain this monotonic queue and the maximum value in this monotonic queue, and use a set to maintain the maximum value.
However, the actual measurement is that it is faster to scan directly than to use set. I don't know how much.

/*=================================
 * Author : ylsoi
 * Problem : Cutting The Sequence
 * Algorithm : DP
 * Time : 2018.5.6
 * ===============================*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<climits>
#include<set>
#include<deque>
#include<ctime>
using namespace std;
void File(){
    freopen("[poj3017]cutting_the_sequence.in","r",stdin);
    freopen("[poj3017]cutting_the_sequence.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define fuck(...) printf(__VA_ARGS__)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf LLONG_MAX
void read(ll &x){
    ll sum=0ll;
    char c=getchar();
    while(c<'0' || c>'9')c=getchar();
    while(c>='0' && c<='9'){
        sum=(sum<<1)+(sum<<3)+(c^'0');
        c=getchar();
    }
    x=sum;
}
const int maxn=1e5+10;
int n;
ll m,a[maxn],sum[maxn],dp[maxn];
void init(){
    scanf("%d%lld",&n,&m);
    REP(i,1,n)read(a[i]);
    REP(i,1,n)sum[i]=sum[i-1]+a[i];
}
deque<int>qu;
multiset<ll>s;
multiset<ll>::iterator it;
void del(ll x){it=s.lower_bound(x);s.erase(it);}
void work(){
    REP(i,1,n)if(a[i]>m){puts("-1");return;}
    int p=0;
    REP(i,1,n){
        int tmp=p;
        while(sum[i]-sum[tmp]>m)++tmp;
        while(qu.size() && qu.front()<=tmp){
            del(a[qu.front()]+dp[p]);
            p=qu.front();
            qu.pop_front();
        }
        if(qu.size()){
            del(a[qu.front()]+dp[p]);
            s.insert(a[qu.front()]+dp[tmp]);
        }
        p=tmp;
        while(qu.size() && a[qu.back()]<=a[i]){
            int bb=qu.back();
            qu.pop_back();
            del(a[bb]+dp[qu.empty() ? p : qu.back()]);
        }
        s.insert(a[i]+dp[qu.empty() ? p : qu.back()]);
        qu.push_back((int)i);
        dp[i]=*s.begin();
        /*dp[i]=inf;
        REP(j,0,(int)qu.size()-1){
            if(j==0)dp[i]=min(dp[i],dp[p]+a[qu[j]]);
            else dp[i]=min(dp[i],dp[qu[j-1]]+a[qu[j]]);
        }*/
    }
    printf("%lld\n",dp[n]);
}
int main(){
    File();
    init();
    work();
    return 0;
}

Guess you like

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