Processing math: 100%

CF1557D.Ezzat and Grid(2200分、线段树)

https://codeforces.com/contest/1557

题意:

给出一个n109的01矩阵。用m个区间表示。(1n,m3×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]+ij1转移过来。

换句话说,对于所有满足条件的j,我们取f[j]+ij1的最小值作为f[i]的答案。

即:f[i]=mini1j=1f[j]+ij1[ij1]

然后把这个式子移项,想方设法让ij独立:

f[i]i=mini1j=1f[j]j1

观察到式子右边只和j有关了。

然后我们考虑如何找满足条件[ij1]j的数量。

可以先对所有区间[i,l,r]做离散化处理,然后用数组a表示两个信息:

ai表示第i个点为1的所有行的最小f[j]j1值和对应j的值。

用线段树维护数组a的区间最小值。

然后在转移的过程中,参考线段树求最长递增子序列的思路,先对当前第i行的所有区间,区间询问数组a的最小值,然后取最小值和那个对应的下标转移给f[i]pre[i]。然后对第i行的所有区间[l,r],用f[i]i1去和区间里的值aimin,即对区间内的每个数aiai=min(ai,f[i]i1)

对于这部分,懒惰标记有点细节处理:

假设我们要使得区间内ai=min(ai,v)

1)如果当前区间的最小值大于v,就更新当前区间的最小值和下标,同时把懒惰标记往下打。

2)如果当前区间的最小值小于等于v,就直接往下打懒惰标记,不修改当前区间的信息。

最后,枚举f[i]+ni的最小值,得到最优答案和最后一个没有被删除的行的位置,根据pre[i]往前递归求出所有没有被删除的行。

剩下的就是被删除的行,输出即可。

posted @   zlc0405  阅读(109)  评论(0编辑  收藏  举报
编辑推荐:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 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)
点击右上角即可分享
微信分享提示