zoukankan      html  css  js  c++  java
  • 【poj3017】 Cut the Sequence

    http://poj.org/problem?id=3017 (题目链接)

    题意

      给出一个数列要求将它分割成许多块,每块的数的和不超过m,要求每块中最大的数之和最小。

    Solution

      这道题真的很不错啊。

      可以很快写出dp方程:${f[i]=min(f[j]+max(a[j+1],a[j+2]···a[i]))}$。数据范围太大,我们必须要想办法优化这个方程。${O(n)}$的状态肯定是没办法优化到${O(1)}$了,想想怎么把转移优化到${O(logn)}$甚至${O(1)}$呢?似乎完全不可做的样子。

      终于还是膜拜了题解,发现:${f[i]}$一定是单调不降的。那么我们对于一个最大的数${a[k]}$,只要选择在它的管辖范围内尽可能靠前的点就好了。什么意思呢,就是:

    设${a[j+1], a[j+2], ...a[i]}$中值最大的下标为${k}$

    设${x}$为${[j+1,k]}$的任意一个下标,则${a[x],a[x+1],....a[i]}$的最大值的下标显然也是k了

    由${f}$的非递减性,${f[j+1] + a[k] <= f[j+2]+a[k].....<= f[k - 1] + a[k]}$ 

    很显然,我们只要取${f[j+1]+a[k]}$就可以了。

      于是我们用单调队列记录一个递减的序列${a[k]}$,因为队首不一定是最优,所以我们还要用平衡树记录${a[k]+f[j]}$来维护它。

      当当前${i}$到队首的距离超过m时,pop队首;当即将插入的元素大于队尾元素时,pop队尾。

    细节

      multiset的运用。

    代码

    // poj3017
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<set>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=100010;
    int q[maxn],a[maxn],n;
    LL m,sum[maxn],f[maxn];
    
    int main() {
    	scanf("%d%lld",&n,&m);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
    	multiset<int> s;
    	int k=0,l=1,r=0;
    	for (int i=1;i<=n;i++) {
    		if (a[i]>m) {printf("-1");return 0;}
    		while (sum[i]-sum[k]>m) k++;
    		while (l<=r && q[l]<=k)
    			{if (l<r) s.erase(a[q[l+1]]+f[q[l]]);l++;}   //超过m
    		while (l<=r && a[q[r]]<=a[i])
    			{if (l<r) s.erase(a[q[r]]+f[q[r-1]]);r--;}   //当前a[i]比队尾元素大,pop队尾元素,并在平衡树中删除
    		q[++r]=i;
    		if (l<r && i>q[r-1])
    			s.insert(a[i]+f[q[r-1]]);
    		int tmp=*s.begin();
    		f[i]=a[q[l]]+f[k];
    		if (l<r && tmp<f[i]) f[i]=tmp;
    	}
    	printf("%lld",f[n]);
    	return 0;
    }
    

      

  • 相关阅读:
    KindEditor简单的Demo使用
    动态从数据库读取菜单(ASP.NET版)
    完全卸载sql2005
    关于在xp(sp3 专业版)下安装sql2005开发版图解
    新手上路Tomcat 7.x和JDK的配置
    关于IE6幽灵字体
    【译】写个好的 CLI 程序
    【译】通过 Rust 学习解析器组合器 — Part 1
    【译】PHP 内核 — zval 基础结构
    【译】PHP 内核 — 字符串管理
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5956429.html
Copyright © 2011-2022 走看看