CF1557D.Ezzat and Grid(2200分、线段树)
https://codeforces.com/contest/1557
题意:
给出一个n∗109的01矩阵。用m个区间表示。(1≤n,m≤3×105)
每个区间包含三个信息:i,l,r。表示在第i行,第l个元素到第r个元素是1。
一个矩阵被称为美丽的,当且仅当,这个矩阵任意相邻的两行,存在一列使得这两行都为1。
询问最少要删除几行使得矩阵是美丽的。
输出删除数量最少的一个删除方案。
题解:
我们定义:
f[i]为在保留第i行的前提下,最少删除几行使得前i行是美丽的。
pre[i]为f[i]表示的状态下,上一个未被删除的行的编号。
那么我们可以枚举i之前的行,设我们当前枚举的是j,如果第i行和第j行有某个位置都是1,那么f[i]可以由f[j]+i−j−1转移过来。
换句话说,对于所有满足条件的j,我们取f[j]+i−j−1的最小值作为f[i]的答案。
即:f[i]=mini−1j=1f[j]+i−j−1[行i和行j有一个位置都是1]
然后把这个式子移项,想方设法让i和j独立:
f[i]−i=mini−1j=1f[j]−j−1
观察到式子右边只和j有关了。
然后我们考虑如何找满足条件[行i和行j有一个位置都是1]的j的数量。
可以先对所有区间[i,l,r]做离散化处理,然后用数组a表示两个信息:
ai表示第i个点为1的所有行的最小f[j]−j−1值和对应j的值。
用线段树维护数组a的区间最小值。
然后在转移的过程中,参考线段树求最长递增子序列的思路,先对当前第i行的所有区间,区间询问数组a的最小值,然后取最小值和那个对应的下标转移给f[i]和pre[i]。然后对第i行的所有区间[l,r],用f[i]−i−1去和区间里的值ai取min,即对区间内的每个数ai,ai=min(ai,f[i]−i−1)。
对于这部分,懒惰标记有点细节处理:
假设我们要使得区间内ai=min(ai,v)。
1)如果当前区间的最小值大于v,就更新当前区间的最小值和下标,同时把懒惰标记往下打。
2)如果当前区间的最小值小于等于v,就直接往下打懒惰标记,不修改当前区间的信息。
最后,枚举f[i]+n−i的最小值,得到最优答案和最后一个没有被删除的行的位置,根据pre[i]往前递归求出所有没有被删除的行。
剩下的就是被删除的行,输出即可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!
2020-08-11 P4116 Qtree3(树链剖分+倍增LCA)
2020-08-11 P3950 部落冲突(树链剖分)
2020-08-11 CF296B Yaroslav and Two Strings(DP)