CF2035D

CF2035D

这道题是 gpt 出的,但是我做不出来,是时候被替代了。

分析

把每个数不断除以二直到得到最小的奇数,记录一下我们能在这个数上提出来的 2 的个数。

首先想到的是贪心地把 2 全部分配给最大的,但是贪心甚至过不了样例。

但是想一想如果 i<j 的限制不存在,我们直接把所有的 2 都分配给最大的处理过后的数 ,那肯定是正确的。

能不能推广到这道题上面来?
当然可以,我们首先还是预处理把所有的数里的 2 都给提出来。

特殊情况

假设有一个子序列,最后一个数就是这个序列里面的最大值,那么是不是就变成了我们提到的 "i<j 的限制不存在"的情况了?
因为显然我们会把所有的 2 都给最后一个数,使得答案最大。

初步思考

仔细想想,这其实是一个单调栈的过程,栈里装的是我们处理过后的数字且递减,对于其中的任意一个元素 stkx ,假设他的上一个元素师 stkx1 ,那么我们一定会把 (stkx1,stkx] 之间的所有 2 都乘给 stkx ,因为显然这是这一部分 2 的最好分配方式了。

进一步思考

你会发现这样应该通过不了样例。

如果说进行完上述操作之后得到的 stkx 就大于 stkx1 了呢?那么我们显然是会把 stkx1 之前的所有 2 也都乘给 stkx 的呀!

实际上这是一个把问题不断划分成子问题的过程。

正序枚举

由于有 i<j 这个限制,那么我们发现,如果正序枚举,当前区间的分配方式对于全局来说,不一定就是最优的,如果后面出现了更大的数,那么当前区间的 2 可以转而分配给后面的区间。

倒序枚举

如果我们倒叙枚举呢?

这时候就可以十分顺理成章地更新出最优答案,而且我们已经算出的答案是不会受前面的影响的。

写法

可是我们显然是不能够对于每一个前缀都去倒叙枚举,这样复杂度就变成 O(n2) 了。

这时候就应该考虑通过继承的方式来快速计算每一个答案,当前加入一个数,我们不断地通过单调栈的模拟把他和前面的合并,直到满足 stkx<stkx1 结束。

Code

小细节

注意在比较 stkxstkx1 的时候不能取模,不然有失正确性,但是由于数据不太强,仍然可以通过前 24 个点。

25 这个点是一个非常好的hack,如下:

Input:
1
3
999999998 2097152 1048576
Expected output:
999999998 2097143 546480318
posted @   Hanggoash  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
动态线条
动态线条end
点击右上角即可分享
微信分享提示