poj3017 Cut the Sequence 单调队列优化dp 好题!

Language: Default
Cut the Sequence
Time Limit: 2000MS   Memory Limit: 131072K
Total Submissions: 8766   Accepted: 2578

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.

Source

POJ Monthly--2006.09.29, zhucheng


题意:给定一个长为n的序列,求一种分割方式使得每部分的最大值的sum最小,求出这个最小值。

思路:设dp[i]为前i个数取得的最小和,那么我们可以有递推公式:dp[i]=min(dp[i],dp[j]+max(a[j+1],a[j+2],...,a[i])) ,其中j<=i 且sum[j]-sum[i-1]<=m。 由于a数组均大于0,那么可以发现数组dp必然是非递减的。 设a[j+1],a[j+2],...,a[i]中的最大值下标为k,由dp的非递减性,dp[j+1]+a[k]<=dp[j+2]+a[k]<=...<=dp[k-1]+a[k].所以我们取dp[j+1]+a[k],也就是说如果某一段到当前位置i的最大值都一样,取最靠前的即可。那么可以联想到单调队列,维护一个递减的队列,存的是符合要求的某一段的最大值。但是需要注意!队首元素不一定是最优的,由于队列的递减性质,队列中的所有元素都有可能组成最优解。详见代码:

#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN=100000+100;
int n,head,tail,pos;
ll m;
int a[MAXN];
ll dp[MAXN];
struct node
{
    int index;
    ll val;
}que[MAXN];
int main()
{
    //freopen("text.txt","r",stdin);
    while(~scanf("%d%lld",&n,&m))
    {
        int flag=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]>m)
                flag=0;
        }
        if(!flag)
        {
            printf("-1\n");
            continue;
        }
        head=tail=0; pos=1;
        ll sum=a[1];
        que[tail].val=dp[1]=a[1]; que[tail++].index=1;
        for(int i=2;i<=n;i++)
        {
            sum+=a[i];
            while(sum>m && pos


你可能感兴趣的:(单调队列优化dp)