[lnsyoj2256]消除游戏
题意
给定序列 ,每次可以选择其中长度 且完全相同的一段并删除,并将序列的剩余部分拼合成一段;或在任意位置插入一个数。求最终将序列 清空的最小操作数
sol
很显然,本题的插入操作是为了能够使一段数能够凑够 个,因此我们可以只考虑删除操作,只在操作上下手脚即可。具体地,我们定义 表示将长度为 的一段删除所需要的最小操作数,显然可得:
本题与[lnsyoj2239/luoguP5336/THUSC2016]成绩单较为相似,都为可以拼合的区间问题。设计 表示将区间 清空,且 之后有 个元素与 相同的最小代价。 我们可以分为三种情况(实际上是两种,分为三种是为了减少细节处理)
- 将 与后面 个值一起删除;
- 将 与后面 个值放在一起();
- 删除区间 ,将 与 及后面 个值放在一起()
综上可得转移方程:
由于数据基本随机,因此实际的可用状态并不多,因此可以使用记忆化搜索。
这里有一个 trick,我们使 表示将区间 清空,且 之后有 个元素与 相同的最小代价,这是因为 这一维的主要目的是为了计算代价,且可以证明,每次将一段相同的区间全部拿完代价最小。这样,我们就将每次初始化所需的时空复杂度缩小到了 。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 405;
int n, m;
int a[N];
int f[N][N][15];
int T;
int cost(int x){
if (x >= m) return 1;
else return m - x + 1;
}
int dfs(int l, int r, int k){
if (k >= m) k = m;
if (f[l][r][k]) return f[l][r][k];
if (l == r) return cost(k + 1);
int res = dfs(l, r - 1, 0) + cost(k + 1);
if (a[r - 1] == a[r]) res = min(res, dfs(l, r - 1, k + 1));
for (int i = l; i < r - 1; i ++ )
if (a[i] == a[r]) res = min(res, dfs(l, i, k + 1) + dfs(i + 1, r - 1, 0));
return f[l][r][k] = res;
}
int main(){
scanf("%d", &T);
for (int u = 1; u <= T; u ++ ) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
memset(f, 0, sizeof f);
printf("%d\n", dfs(1, n, 0));
}
return 0;
}
分类:
题解 / 2024赛时
标签:
DP
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现