poj 3017 Cut the Sequence dp 单调队列+set

http://poj.org/problem?id=3017

poj  3017 Cut the Sequence

 

 对我来说……挺不好理解的一道题…………

 

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
using namespace std;
const int maxn= 100005;
const int INF= 0x3f3f3f3f;
long long dp[maxn], m;
int a[maxn], n, q[maxn];
multiset<long long> tree;
void dynamic(){
    int i, j, k, h, r, lef= 1, flag= 1;
    long long sum= 0;
    h= 0, r= -1;
    /*
        状态转移方程:
        dp[i]= dp[lef-1] + max(a[lef]...a[i])
        用单调队列q维护区间最大点,元素值及下标都单调递减
        sbt维护最优值,堆顶为最小值
    */
    for( i= 1; i<= n; i++){
        sum+= a[i];
        while( sum > m) sum-= a[lef++]; //求最左可以分为一组的点
        if( lef > i){
            flag= 0;
            break;
        }
        while( h <= r && a[q[r]] <= a[i] ){//单调队列中找到i的位置
            /*
                删除sbt中不符合的数据
                若去q[r]删除掉,则对应的sbt中的dp[q[r-1]] + a[q[r]]项也应去掉
                其中,a[q[r]]为[q[r], i-1]的最大值,但a[q[r]]同样也大于a[q[r-1]]
                即dp[i-1]= dp[a[q[r-1]]] + max(a[q[r-1]]...a[q[r]]...a[i-1])为sbt中被删除的值
            */
            if( h < r)
                tree.erase(dp[q[r-1]] + a[q[r]]);
            r--;
        }
        q[++r]= i; //i点存入队列
        if( h < r) tree.insert( dp[q[r-1]] + a[q[r]]);//新更新的队列的队首值加入队列,但不一定是目前最优值
        while( q[h] < lef){// 队首元素不在区间内时删除,维护单调队列取值在规定范围内
            if( h < r)
                tree.erase( dp[q[h]] + a[q[h+1]]);//sbt中删除不在范围内的点的值,a[q[h+1]]为(q[h], i]中的最大值
            h++;
        }
        dp[i]= dp[lef-1] + a[q[h]]; //下限值特判
        if( h < r && dp[i] > *(tree.begin())) dp[i]= *tree.begin();
        cout<<i<<"  "<<dp[i]<<"  "<<dp[lef-1] + a[q[h]]<<"  "<<(*tree.begin())<<endl;;
    }
    if( flag)printf("%I64d\n", dp[n]);
    else printf("-1\n");
}
int main(){
   //freopen("1.txt", "r", stdin);
    int i, j, k;
    while( scanf("%d%I64d", &n, &m) != EOF){
        a[0]= dp[0]= 0;
        for( i= 1; i<= n; i++){
            scanf("%d", &a[i]);
        }
        dynamic();
    }
    return 0;
}
发布了69 篇原创文章 · 获赞 1 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章