T1:
给出数组 ,表示 "长度 的 LIS 的末尾最小元素"(也就是原序列的 LIS 长度为 )。构造一个长度 值域 的原序列满足 的限制,或判定无解。
一种显然的构造方式:把 数组整个放到原序列最后 个,然后从开头从大往小填。先不断填 ,如果发现再填就会把对应长度的 破坏掉,就开始填 ……
T2:
给定一棵树,初始有棋子在根结点。两人轮流操作,A 可以把某叶子染黑,B 可以把棋子挪到相邻结点。问最优策略下,B 能否把棋子挪到一个非黑色的结点。
表示当前棋子在 ,往 的子树里走,A 至少提前染黑多少个叶结点才能保证赢。可以 DP。同时注意 。
T3:
对于一个字符串 ,定义操作 :在 的每个空里都插入一个 。
给定一个操作序列 ,问 有多少个本质不同的子序列。
反向考虑一种操作 ,这样操作等价于 做一遍。
令 表示当前字符串有多少个子序列以 开头,且末尾加上 之后就不再是子序列。
当两个字符串 合并为 时,其 的变化:。(其实就是矩阵乘法的形式)
可以看作两次字符串合并。
为了方便,给字符集添加一个不存在的字符 #
, 记录了所有以 开头的子序列个数。
总共 次合并,一次合并 ,总复杂度 。
T4:
给定一个 的网格图,第一行的第 个点和第二行的第 个点有连边。 构成一个排列。删掉第 条边的代价为 ,同时会把当前所有与它相交的边一起删掉。问删光的最小代价是多少。。
一个观察是,如果最终选择的边是 ,则 。同时 之间 不存在数 使得 。
为了方便,不妨额外建立 两条无代价的边。
由此导出一个 DP: 表示考虑前 条边全部删光的最小代价,强制 删。转移则枚举 为上一条决定删的边。
这个复杂度是 的。
分治,先递归进左半边求出左半边的 DP 值。然后考虑左半边某个点作为右半边某个点的前置状态做的贡献。再递归进右半边求出右半边的 DP 值。
问题在于中间的。把左右点取出,各自按照 排序。同时维护左右两个单调栈,左边的单调栈保证 递减,右边的单调栈保证 递增。左边的单调栈保证了都有相交,可以用来更新;右边的单调栈保存了所有可能使得不能更新的可能性,即所有会限制左边点更新的点。
两个指针初始指向左右数组的开头,每次从两个指针中取出 较小的更新:
-
若取出左边的点 ,则在 的位置上标记一个 。(在 pop 的时候把对应位置标记为 )
-
若取出右边的点 ,先 pop,假设此时栈顶的点第一行 ,则查询 这个区间内所有标记的最小值,然后把 加入栈。
用一个线段树即可。
复杂度 。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 易语言 —— 开山篇