POJ 3017 Cut the Sequence

Cut the Sequence

Time Limit: 2000MS Memory Limit: 131072K
Total Submissions: 10240 Accepted: 3093

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


【分析】
给定长度 为N的序列,把它分成若干段每和不超过 M,问 分成的所有段里最大值和小是多少?
• f[ i]=min(f[j]+max(a[ j+1]…]=min(f[j]+max(a[ j+1]…]=min(f[j]+max(a[ j+1]…]=min(f[j]+max(a[ j+1]…]=min(f[j]+max(a[ j+1]…i])) ,其中 ∑(a[ j+1]…(a[ j+1]…(a[ j+1]…i])<= M,O(n^2) O(n^2) 。
• 引理:上述方程中决策 j是必要的,当 且仅a[j] 是j到i这一段里的最大值。
• 证明:反证法。记 Max[ j,i ]为j到i的最大值 ,若 Max[ j,i ]=Max[j+1,i ]=Max[j+1,i ]=Max[j+1,i],由f数组的单调性 f[j -1]<=f[j],得到 f[j -1]+Max[ j,i ]<= f[j]+Max[j+1,i] ,这就 说明决策 j一定不如决策 j-1更优 ,与 决策 j是必要的 矛盾,证毕。

• 可以 维护一个 a[ i]值单调递减的 队列 q,该队列 中的 决策都是 必要的 。易 知f[q[k-1]]+a[q[k]](L < k<=R )就是可以对 f[i]进行更新的决策值。

q并不 满足决策值单调,所以要遍历队列取最优解,同时还要手动特殊维护一个队首的决策指针。

题上说要用I64,其实long long也可以。


【代码】

//poj 3017 Cut the Sequence
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
ll dp[mxn],sum[mxn],q[mxn],a[mxn],g[mxn];
ll m;
int n;
int main()
{
    bool flag=0;
    int i,j,k;
    scanf("%d",&n);
    scanf("%I64d",&m);
    fo(i,1,n)
    {
        scanf("%I64d",&a[i]);
        if(a[i]>m) flag=1;
        sum[i]=sum[i-1]+a[i];
    }
    if(flag) {printf("-1\n");return 0;}
    memset(dp,0x7f,sizeof dp);
    dp[0]=0;
    int h=1,t=0,shit=1;
    fo(i,1,n)
    {
        while(sum[i]-sum[shit-1]>m) shit++;
        while(h<=t && a[q[t]]<=a[i]) t--;
        q[++t]=i;
        while(h<=t && sum[i]-sum[q[h]-1]>m) h++;
        dp[i]=min(dp[i],dp[shit-1]+a[q[h]]);
        k=shit-1;
        fo(j,h,t)
        {
            ll tmp=dp[k]+a[q[j]];
            dp[i]=min(dp[i],tmp);
            k=q[j];
        }
    }
    printf("%I64d\n",dp[n]);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值