码迷,mamicode.com
首页 > 其他好文 > 详细

Cut the Sequence

时间:2019-06-01 11:13:40      阅读:112      评论:0      收藏:0      [点我收藏+]

标签:getch   单调队列   c++   print   序列   nlogn   最小值   最大值   pac   

POJ

题意:给定一个长度为N(\(N<=10^5\))的序列A,要求把该序列分成若干段,在满足"每段中所有数的和"不超过M(\(M<=10^{11}\))的前提下,让"每段中所有数的最大值"之和最小.求出最小值.

分析:设\(f[i]\)表示把前i个数分成若干段且满足条件的最小值.

\(f[i]=min_{0<=j<i,\sum_{k=j+1}^iA_k<=m}f[j]+max_{j+1<=k<=i}A_k\)

二分\(nlogn\)预处理出对于每个i,满足\(\sum_{k=j+1}^iA_k<=m\)的最小的j值,记为\(c[i]\).

对于\(max_{j+1<=k<=i}A_k\)采用单调队列优化.

处理好了以上两个就可以直接转移了\(f[i]=f[c[i]]+a[q[l]]\)

如何计算\(max_{j+1<=k<=i}A_k\)?有两种方法,一是ST,二是利用本题单调队列性质,队列中某一项的\(max_{j+1<=k<=i}A_k\)就是队列下一个元素的A值.(方法一易证难写,本人搞了半个多小时还是WA;方法二不知道证但容易写,一行代码.)

记得开long long...

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define LL long long
using namespace std;
inline LL read(){
    LL s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
const int N=100005;
LL a[N],c[N],q[N],f[N],sum[N];
int main(){
    LL n=read(),m=read();int bj=1;
    for(int i=1;i<=n;i++){
        a[i]=read();
        if(a[i]>m)bj=0;
        sum[i]=sum[i-1]+a[i];
    }
    if(!bj){puts("-1");return 0;}
    for(int i=1;i<=n;i++){
        int l=1,r=i,mid,cnt;
        while(l<=r){
            mid=(l+r)>>1;
            if(sum[i]-sum[mid-1]<=m)cnt=mid,r=mid-1;
            else l=mid+1;
        }
        c[i]=cnt-1;
    }
    int l=1,r=0;
    for(int i=1;i<=n;i++){
        while(l<=r&&a[q[r]]<=a[i])r--;
        q[++r]=i;
        while(l<=r&&q[l]<=c[i])l++;
        f[i]=f[c[i]]+a[q[l]];
        for(int j=l;j<=r;j++){
            f[i]=min(f[i],f[q[j]]+a[q[j+1]]);
        }
    }
    printf("%lld\n",f[n]);
    return 0;
}

Cut the Sequence

标签:getch   单调队列   c++   print   序列   nlogn   最小值   最大值   pac   

原文地址:https://www.cnblogs.com/PPXppx/p/10958822.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!