poj 3017 Cut the Sequence 好题好题

Cut the Sequence
Time Limit: 2000MS Memory Limit: 131072K
Total Submissions:11012 Accepted: 3359

Description

Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subsequence of the original sequence. Every part must satisfy that the sum of the integers in the part is not greater than a given integer M. You are to find a cutting that minimizes the sum of the maximum integer of each part.

Input

The first line of input contains two integer N (0 < N ≤ 100 000), M. The following line contains N integers describes the integer sequence. Every integer in the sequence is between 0 and 1 000 000 inclusively.

Output

Output one integer which is the minimum sum of the maximum integer of each part. If no such cuttings exist, output −1.

Sample Input

8 17
2 2 2 8 1 8 2 1

Sample Output

12

Hint

Use 64-bit integer type to hold M.


#include <iostream>
#include <cstdio>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
using namespace std;

#define rep(x,y) for(int i=x;i<=y;i++)
#define repp(x,y,m,n) rep(x,m)rep(y,n)

typedef long long ll;

const int MAX=100000+5;
ll N,M;
int a[MAX];
int deq[MAX];
ll dp[MAX];

void print(){
    for(int i=1;i<=N;i++){
        cout<<dp[i]<<" ";
    }
    cout<<endl;
}

void solve(){

    scanf("%lld %lld",&N,&M);
    bool f=0;
    for(int i=1;i<=N;i++){
        scanf("%d",&a[i]);
        if(a[i]>M){
            f=1;
        }
    }
    if(f){
        printf("-1");
        return;
    }

    int h=1,t=1;

    int j=1;
    ll sum=0;
    for(int i=1;i<=N;i++){

        while(h!=t&&a[deq[t-1]]<=a[i]){
            t--;
        }
        sum+=a[i];
        deq[t++]=i;

        while(sum>M){
            sum-=a[j++];
        }

        while(deq[h]<j){
            h++;
        }

        dp[i]=dp[j-1]+a[deq[h]];
        for(int k=h+1;k<t;k++){
            dp[i]=min(dp[i],dp[deq[k-1]]+a[deq[k]]);
        }


       // print();

    }

    printf("%lld",dp[N]);


    return;
}


int main(){

    solve();
    return 0;
}






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值