P9746 「KDOI-06-S」合并序列 (区间dp)

P9746 「KDOI-06-S」合并序列

upd 2024.11.13

经典区间dp+预处理

只要是做了入门区间 dp 的人都应该看出来。

怎么优化呢?发现了转移时枚举了冗杂转移,原因是可达性 dp 的转移只需要找到一个合法转移即可。

怎么找到一个合法转移?

这时候可以试试预处理一些信息加速转移。也可以说是一段一段处理问题。

不难设计状态 fl,r 表示 [l,r] 能否变为一个数,转移也简单,枚举三个区间,满足 fi,a=fb,c=fd,r=1 且异或和为 0。复杂度为 O(n6)

设异或和为 sl,r

考虑优化,瓶颈在于转移需要枚举三个区间。假如只枚举一个右区间 [d,r],那么我们只需要判断 [l,d1] 中是否存在两个区间能缩成一个数且两区间异或和为 sd,r 就可以转移。

直接设 hi,j 表示满足 iabcsi,asb,c=j 的最小 c 值。但发现还是不好预处理出来,不好找到 [b,c] 区间。再设 gi,j 表示满足 iabsa,b=jfa,b=1 的最小 c 值,g 容易转移,而 h 只需要枚举 a 即可,hi,si,aj=minga+1,j (fi,a=1)

f 转移变为存在 ldr,满足 hi,sd,r<d 。单次复杂度为 O(n2A),注意当前 fl,r1 后可以直接 break。

h 数组和 g 数组的转移在区间 dp 时更新即可。值得注意的是,在这题中,区间 dp 的顺序只能是左端点 l 从右向左枚举,右端点 rln 枚举,因为 h 数组和 g 数组的更新需要之前所有长度的 fl,r,如果只按长度更新会出现错误,如枚举 l=a=1 时,若按长度枚举,无法转移到 ga+1,j 长度大于 1 时的区间。

对于输出方案,除了记录每个区间的前继,还需要记录 hg 数组转移时的其中一个合法方案,对于编号的改变,这个体现在 dfs 中。这个输出方案还是比较重要的。

void print(int l, int r, int id) {
	if(l == r || l == 0) return;
	int d = pre[l][r], a = hl[l][sum[r] ^ sum[d - 1]];
	int now = sum[a] ^ sum[l - 1] ^ sum[r] ^ sum[d - 1];
	int b = gl[a + 1][now], c = g[a + 1][now];
	print(d, r, id + (d - l)), print(b, c, id + (b - l)), print(l, a, id);
	ans.push_back({id, id + (b - l) - (a - l), id + (d - l) - (a - l) - (c - b)});
}

对于 hg 出现的动机还是挺明确的,一个是优化需要,一个注意到 ai 的大小,就知道可以把它放进状态里了。转移需要注意。

posted @   Fire_Raku  阅读(28)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示