最小M段和 O(nlogn)快速算法

本文探讨了一道经典的数列分割问题,通过分析其特点,采用基于二分搜索的动态规划算法,最终实现了高效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先声明,这算法我还没弄出来

 

 

 

《数列分割》解题报告

[题目描述]

给出一个长为N的整数数列(N≤15000),要求求出最小的M,使得存在一种将数列分成恰好K份的方案(每份是数列上连续的一段,且不得为空),每份的数字之和不大于M

题目来源:Viet Nam Olympiad in Informatic 2005, Day I

[算法分析]

此题又是典型的要求最大值尽量小的形式,对于这样的问题,往往可以使用基于二分的算法解决。对于此题,则是二分枚举M的值,再判断对于这个M是否存在划分方案并缩小范围。

此题的难度在于,数列中可能存在负数,那么当数列的一个前缀的数字和已经大于M时,更后面的前缀和仍然有可能小于M(因为负数)。另外,对于一个特定的M,如果数列存在划分为K-1份的方案,并不一定存在划分为K份的方案,例如数列 -1 -1 -2,对于M-2,存在划分为2份的方案,却不存在划分为3份的方案。这样,一些常用的简单算法将不再适用。

在找不到有效算法时,先来看看朴素的算法。对于是否存在一种恰好K份的划分方案,使得每一份的数字和不大于M”这一问题,很容易设计出这样一个动态规划算法:

S[i]表示原数列前i个数构成的子序列,Sum[i]表示S[i]中所有数字之和。定义f[i][j]表示是否存在将S[i]划分为恰好j份的方案,其中每一份的数字之和不大于Mf[i][j]都为truefalse

对于j0f[i][j]当且仅当i0时为true,其余为false

对于i0f[i][j]当且仅当j0时为true,其余为false

对于j>0i>0f[i][j]f[i1][j-1] or f[i2][j-1] or … or f[il][j-1]ix是所有在[0i-1]范围内且满足Sum[i]-Sum[ix]≤M的整数。

这个算法的时间复杂度高达ON3),对于本题数据范围无法承受。但是容易发现,这个模型中状态形式简单(布尔类型),转移方程也比较特殊,可能会存在一些内在的规律。那么现在我们来深入研究这个动态规划模型。

转移方程的第一个特殊之处在于,对于同样的i不同的j,方程中的i1…il的值都是相同的

 

正在处理的是i7一行,对于这一行中的每个格子(状态),它的值由前面行中和它同色格子的值进行or运算得到,由于转移方程的特殊形式,就成了上图那样的形态。如果将每一行看成一个布尔向量,那么计算第i行实际上就是先找出i1…il,再将这l个向量相加(此处是or运算),并向右位移一位,最高位舍弃(实际上一定为false),最低位补0,就得到了第i个向量。

不过这一认识暂时不能帮助降低算法的时间复杂度,还需要更多的东西。回到转移方程中,观察i1…il这个集合,它看似是散乱的,其实不然,它是ix<iSum[i]-Sum[ix]≤M的集合,即Sum[i]-M≤Sum[ix],如果将0i-1行按照Sum值从大到小排序,那么i1…il对应的实际上就是前l

 

那么进行到第i行时,可以在0i-1行使用二分查找找出转移所涉及的行,将他们or起来、右位移得到第i行的结果,再将第i行插入到合适的位置,保持0i行按Sum降序排列。

上面的描述涉及的操作有:二分查找一个位置、将元素(布尔向量)插入到某个空的位置、求某个位置前所有向量or起来的值。这是典型的可以使用离散化+树状数组解决的问题,但是,由于操作的元素是向量,基本操作就有ON)的代价,导致算法的时间复杂度为ON2 log N),空间复杂度为ON2),对于本题的数据范围无法承受。

回到前面的算法分析,对于第i行,它的值是通过前面连续的lor起来再进行一次位移得到的,如果将得到的值和前面l行再or起来,相当于把一个向量右位移一个单位再和自己or起来,给人直观的感觉是,向量里的true不会变得更零散,而有可能变得更连续,特别地,如果这个向量里的true本来就是连续的一段,右位移再or的结果仍然是连续的。另外,第一行是连续的(只有1true),这启发我们可以使用数学归纳法来得到一些东西。稍作分析就能得到,在算法进行的任意时刻,任意一个向量里的true都是连续的,且按Sum值倒排后前任意多个连续向量or起来的结果里的true也是连续的。

有了这个结论,我们就可以使用一个整数对来描述一个向量:(XY)表示向量中从XY这一段为trueor运算和位移运算都可以简单地实现:

X1Y1orX2Y2)=(minX1X2),maxY1Y2))

XY>>1=(X1Y1

将这样的表示法用到前一个算法中,就得到了时间复杂度ON log N)、空间复杂度ON)的可行算法。

[总结]

本题具有这样低复杂度的算法的关键原因在于,每个向量里的true都是连续的,跳出上文的语境,就得到了一个数学命题:

要求将一个数列划分为每份数字之和不大于M的若干份,如果同时存在划分为A份和B份的方案,那么也存在划分为[AB]中的每一个份数的方案。

上文实际上证明了这个结论,但是通过了朴素的动态规划算法搭桥。惭愧的是我并没有找到使用纯数学工具进行证明的方法,希望各位大牛不吝赐教。

 

 

 

 

感谢xqz提供的程序

 

 

 

 

马上我就自己打一边然后发出来,不会让大家看这么丑的程序的......

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值