Luogu5611 Ynoi2013 D2T2/牛客挑战赛32F 最大子段和 分块、分治

传送门


之前一直咕着的,因为一些特殊的原因把这道题更掉算了……

有一个对值域莫队+线段树的做法,复杂度O(nnlogn)然而牛客机子实在太慢了没有希望(Luogu上精细实现似乎可以过)。

考虑对序列进行块大小为B=n的分块。对于某一个块来说,如果我们要对这个整块进行询问,那么一次询问一定会保留这B个数按照值域排序之后的一段区间,其余都变成0。也就是说本质不同的询问只有O(B2)种。

如果可以对这O(B2)种询问处理出每一种对应询问下这一块中的最大子段和、最大前缀和、最大后缀和和总和,那么对于一组询问就只需要把整块的信息拿过来把散块暴力合并就可以了。

注意到计算最大子段和具有结合律,我们考虑分治。当我们在解决一段区间(l,r)时候,先从中间劈成(l,mid)(mid+1,r)两半递归下去做,递归边界是l=r。接下来我们考虑当我们解决了(l,mid)(mid+1,r)的问题时如何合并。

首先我们可以使用归并得到当前区间按照值域排序后的数组,然后我们需要通过左右两边得到的答案来得到左右端点分别取在其中某个位置的时候的答案。假设需要求值域左右端点为(l,r)的答案,那么在左区间中找到最小的l的值l1和最大的r的值r1,那么对于左区间来说询问(l,r)等价于询问(l1,r1),而后者在之前处理的答案里面存在。所以我们找到l1,r1就可以得到左区间的信息,右区间同理。我们可以通过这个方式来得到当前区间下的所有答案。

使用单调性将每一层合并的复杂度降低为区间长度的平方,那么分治的复杂度可以由T(n)=2T(n2)+O(n2)计算,根据主定理T(n)=O(n2)。也就是我们将所有块的答案预处理出来的复杂度是O(nn)的。

然后我们只需要对于每一次询问找到每一块内这组询问的值域区间对应在块上的哪一个区间。在线做需要二分,所以可以把询问离线下来,把所有需要求位置的所有值域位置先排序然后双指针求出对应位置。复杂度O(nn)

题外话:这东西常数贼大,尽量避免使用STL是卡常的很好的选择……

Code

posted @   cjoier_Itst  阅读(603)  评论(2编辑  收藏  举报
编辑推荐:
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)
点击右上角即可分享
微信分享提示