[CF83E] Two Subsequences 题解
[CF83E] Two Subsequences 题解
思路
定义
观察到每次操作之后,一定有一个序列是以
所以根据这个性质设计状态:
但是这个状态设计并不好,因为没法进一步优化,发现
所以可以列出这个状态表示:
推出状态转移方程为:(为了方便书写,这里省略和状态原值取
-
第一个转移代表把
和 放到同一个序列里面; -
第二个转移代表
和 不在同一个序列里面,这种情况下要枚举另一个序列结尾本来是什么来转移。
这样是
首先发现第一个转移是对所有的
那么瓶颈就到了第二个转移上面,发现第二个转移的特点是只有一个状态发生了改变,并且每次加上的值都介于
这样就可以把第二个转移写成:
进一步发现第二个
把
这样如果得到了
如何得到
之后进行滚动数组优化即可通过此题。
实现
注意一些细节,所有的
时间复杂度:
// Problem: Two Subsequences
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-12-06 22:07:10
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 2e5 + 10;
string a[N];
int n, m, f[(1 << 20) + 5], g[22][(1 << 20) + 5], tag;
int overlap(string a, string b) {
for(int i = m; ~i; i --) {
bool flg = 1;
for(int j = 0; j < i && flg; j ++)
if(a[m - i + j] != b[j]) flg = 0;
if(flg) return i;
}
return 0;
}
int change(string x) {
int t = 0;
for(int i = 0; i < m; i ++)
t = t * 2 + (x[i] - '0');
return t;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
m = a[1].size();
memset(f, -0x3f, sizeof f), memset(g, -0x3f, sizeof g);
for(int i = 2, delta = 0; i <= n; i ++) {
delta = overlap(a[i - 1], a[i]);
int now = change(a[i - 1]);
tag += delta;
f[now] = max(-delta, f[now]); // 这个转移来自于那些本来第二个序列里面没有放东西的
for(int j = 0, t = 0; j <= m; j ++) {
f[now] = max(f[now], g[j][t] + j - delta);
if(j < m) t = t * 2 + (a[i][j] - '0');
}
for(int j = 0, t = 0; j <= m; j ++) {
g[j][t] = max(g[j][t], f[now]);
if(j < m) t += (1 << j) * (a[i - 1][m - j - 1] - '0');
}
}
int ans = tag;
for(int i = 0; i < (1 << m); i ++)
ans = max(ans, f[i] + tag);
cout << n * m - ans << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现