首页 > 其他分享 >poj3017 Cut the Sequence

poj3017 Cut the Sequence

时间:2023-11-20 16:55:05浏览次数:31  
标签:Cut poj3017 Sequence read ll 决策 int integer include

 

Cut the Sequence
Time Limit: 2000MS   Memory Limit: 131072K
Total Submissions: 15419   Accepted: 4735

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


朴素的方程非常简单
f[i]=max(f[j]+max(a[k]))  (sum(a[k])<=M,i<=k<=j)

数据结构没法优化
只能够加速求max和sum,这个很简单,很基础,但是对决策和转移没有明显的优化
O(n^2)的复杂度没变
看看有没有没必要的转移
好像有一个贪心
就是每一段都要尽可能的取满
这是有误的,样例就是反例

那就是要么尽可能装满,要么尽可能装大的
“装大的”这个具体的式子怎么写?
好像明白了,1 8 1 8 2 2 2,然后m=17

尽可能装大的其实是尽可能不往小的里面塞大的
现在要做的就是维护只含这两种转移的决策集合
链表+二分好像可以,还是O(n^2),主要是塞大的这个转移不好搞
这个最大值取的区间好像是单调移动的
可以单调队列?
很像,但不完全是吧
这个单调队列的队头不是最优决策,全部枚举一遍相当于没优化
那就再套一个数据结构吧
每次可以取出我们要的最优决策,盲猜logn复杂度
总体O(nlogn)

事实上我两个都写了,然后很妙,O(n^2)172ms,O(nlogn)972ms
这可是1000000啊

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <string.h>
#include <set>
#define ll long long
using namespace std;
inline ll read() {
    char c=getchar();ll a=0,b=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
int n;ll m;int f[1000001],a[1000001];ll pre[1000001];
int que[1000001],head,tail;
multiset<int> pq;
int main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        pre[i]=pre[i-1]+a[i];
        if(a[i]>m)
        {
            cout<<"-1"<<endl;
            return 0;
        }
    }
    head=1,tail=0;
    int nw=1;
//    multiset<ll> pq;
    for(int i=1;i<=n;i++)
    {
        while(pre[i]-pre[nw-1]>m)nw++;
        while(head<=tail&&a[que[tail]]<a[i])
        {
            if(head<tail)
            pq.erase(f[que[tail-1]]+a[que[tail]]);//Èç¹ûÊÇ×îºóÒ»¸ö£¬ÕÒ²»µ½Õâ¸öf+aµÄÖµ£¬¶øÇÒ×îºóÒ»¸öÆäʵÊÇûÓÐÒâÒåµÄ 
            tail--;
        }
        que[++tail]=i;
        
        if(head<tail)pq.insert(f[que[tail-1]]+a[i]);//¸Õ¸Õ²åÈëµÚÒ»¸ö£¬Ã»ÓеڶþÖÖתÒÆ£¬¶¼ÊǵÚÒ»ÖÖ 
        while(head<=tail&&que[head]<nw)
        {
            if(head!=tail)pq.erase(f[que[head]]+a[que[head+1]]);
            head++;
        }
        f[i]=f[nw-1]+a[que[head]];//µÚÒ»ÖÖתÒÆ 
        if(head<tail)f[i]=min(f[i],*pq.begin());
    }
    cout<<f[n]<<endl;
    return 0;
}
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <string.h>
#include <set>
#define ll long long
using namespace std;
inline ll read() {
    char c=getchar();ll a=0,b=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
int n;ll m;int f[1000001],a[1000001];ll pre[1000001];
int que[1000001],head,tail;
multiset<int> pq;
int main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        pre[i]=pre[i-1]+a[i];
        if(a[i]>m)
        {
            cout<<"-1"<<endl;
            return 0;
        }
    }
    head=1,tail=0;
    int nw=1;
//    multiset<ll> pq;
    for(int i=1;i<=n;i++)
    {
        while(pre[i]-pre[nw-1]>m)nw++;
        while(head<=tail&&a[que[tail]]<a[i])
        {
            tail--;
        }
        que[++tail]=i;
        while(head<=tail&&que[head]<nw)
        {
            head++;
        }
        f[i]=f[nw-1]+a[que[head]];//µÚÒ»ÖÖתÒÆ 
        for(int j=head;j<tail;j++)
        {
            f[i]=min(f[que[j]]+a[que[j+1]],f[i]);
        }
//        pq.insert(f[que[tail]-1]+a[que[tail]]);
    }
    cout<<f[n]<<endl;
    return 0;
}

 

 

单调队列好像是只要取的是最大值就可以了
存活能力这个比喻真的算是说出了本质了
单调队列可以在满足无数个条件的情况下取出最优的最值
唯一的限制就是,某一个状态一旦不再满足其中一个条件,那它就再也不会满足这个条件了
这是保证了决策区间的单调移动
毕竟是O(1)的优化,限制大点没问题。。
这个单调队列更加的广义吧
里面不在是最优的决策集合,而是可以使用的决策集合
这个因为单调性可能只是体现在可能的决策集
这种优化只需满足上面说的一种限制:某一个状态一旦不再满足其中一个条件,那它就再也不会满足这个条件了
而之前的那种O(1)的优化则需要满足再这种情况下,位置越前的决策是越优秀的

似乎可以更加的扩展?
为了方便使用队列即使的删除掉不可用的决策,我们的队列必须要按照“生存能力”排序,也就是队头处的决策总是会先离开合法范围
那如果我们的条件多了呢?
那不就不一定从队头弹出了
那我们需要一个能够按照某个顺序(也就是要求)快速查找我们需要的元素,并且支持动态的删除和添加元素
平衡树。。
平衡树优化dp。。。
想想都难绷啊
但是其实这种题目是强套的,就是解构过后,知道平衡树的人是能够直接写出来的
这种东西也有限制,因为大概率对于不同的限制,顺序并不会按照同一个,也就是查找可能并不通用
能够转换排序关键字的平衡树。。如果转换的关键字没有联系,那就是O(nlogn)
所以如果这个关键字有联系
那就可以转换了?可以的,我会出黑题了


我发现我现在写dp方程都不想想贪心的可能的
太快了,应该多思考一下再想想dp的可能,根本就没去排除贪心

标签:Cut,poj3017,Sequence,read,ll,决策,int,integer,include
From: https://www.cnblogs.com/HLZZPawa/p/17844339.html

相关文章

  • Knative Eventing Sequence Flow 示例
    环境说明◼PingSource负责生成event◼Event由Sequence中的各Step顺次处理◆各Step都运行一个appender应用◆分别向收到的数据尾部附加自定义的专有数据项◼最终结果发往ksvc/event-display环境示意图创建名称空间#kubectlcreatenssequence-demonamespace/seq......
  • [ABC328C] Consecutive 题解
    HelloWorld链接这道题是一个很明显的前缀和,我们把$sum_i$表示为前$i$个字符有多少个有重复,查询的时候就用$sum_{r-1}-sum_{l-1}$就行了。代码#include<bits/stdc++.h>usingnamespacestd;strings;intsum[300010];intmain(){ intn,q; cin>>n>>q>>s; for(in......
  • CF222A Shooshuns and Sequence 题解
    分析这题是一个很水的题,就是对一个序列有$2$种操作方法,一种是对第$K$个数以前的数的第一个进行删除,另一个则是在整个序列后添加这第$K$个数,使得整个序列为同一个数字,显然,后者是无效操作,则只需要判断第$K$个数以后有无与第$K$个不同的数,有则无解,反之有解。若有解,然后再......
  • CF601B Lipshitz Sequence 题解
    给你一个序列\(v_{1\dotsn}\),定义\(f(v)\)为\(v\)中斜率最大值(\(\lvertv\rvert=1\)则\(f(v)=0\)),有\(q\)组询问,每次给定\(1\lel\ltr\len\),求\(a_{l\dotsr}\)的每个子区间的\(f\)之和。一个关键的性质是,最大的斜率只在相邻数间取到。有了这个性质,这题......
  • 2023-11-17 记录formly+antd+dayjs的shortcuts设置筛选项全部、昨天、今天
    业务中需要用到formly+antd的组件DatePicker日期组件,其中要给该组件添加筛选项(如:全部、昨天、今天),日期的格式化用到了日期插件dayjs(注意不是momentjs)shortcuts=[{text:'全部',onClick:()=>([null,null])},...shortcutsData]如果只是设置昨天或者今天,只需传开始和结束......
  • [USACO22OPEN] Up Down Subsequence P
    [USACO22OPEN]UpDownSubsequenceP注意到这个问题是不弱于直接求LIS的,因此考虑dp。设\(f_i\)表示以\(i\)结尾的最长这个什么串的长度,显然没办法直接转移,那么暴力的想法就是多设一维,这样自然就寄了。我们考虑到这样一件事情:如果我们假装对于所有的\(j\),\(j<f_i\)时......
  • shell脚本之“sort“、“uniq“、“tr“、“cut“、“split“、“paste“以及“eval“
    一、sort命令1.1、作用以行为单位对文件内容进行排序也可以根据不同的数据类型来排序1.2、语法格式sort[选项]参数catfile|sort选项1.3、常用选项-f∶忽略大小写,会将小写字母都转换为大写字母来进行比较;-b∶忽略每行前面的空格;-n∶按照数字进行排序;-r∶反向......
  • husky——The '.husky/pre-commit' hook was ignored because it's not set as execut
    前言系统:machint:The'.husky/pre-commit'hookwasignoredbecauseit'snotsetasexecutable.hint:Youcandisablethiswarningwith`gitconfigadvice.ignoredHookfalse`.hint:The'.husky/prepare-commit-msg'hookwasignoredbec......
  • G - Cut and Reorder 状压DP
    我是题目链接首先显然先一操作,然后二操作这样不会影响最终结果一眼状压DP,选出一些a从前往后塞,f[i][j]表示选出的a状态为i,且结尾为j时最小花费转移就看上一个状态的结尾(设为k)和当前结尾(设为j)在a里的下标是否顺着挨着(就是j=k+1),不是顺着挨着就要加个c这样会tle#include<bits/std......
  • [题解] CF407E k-d-sequence
    k-d-sequence给你一个长为\(n\)的序列,求最长的子区间使得它加入至多\(k\)个数后,重排后是公差为\(d\)的等差数列。\(n,k\le2\times10^5\),\(0\led\le10^9\)。公差是\(d\)的等差数列模\(p\)的值应该相等,所以把序列按极长模\(p\)同余的连续段分组。对于同......