1 条题解
-
0
首先考虑一个时空复杂度都是 的做法:
首先求出 中的每一个数下一次的出现位置 。类似于正常的 LCS,设 为考虑 的前 项, 的前 项的最长公共口吃序列长度,考虑向后转移,显然有以下转移:
- ,;
- 特别地,若 ,则 。
由于空间限制只有 32MB,而当前的状态转移又无法进行滚动数组优化,考虑重新设计状态。
仔细分析转移过程,考虑如何将第二步写成能够滚动数组优化的形式。现在的转移过程是 ,,不如我们先将 一步移动到 ,并对当前状态进行标记,代表 目前只匹配了一次,在转移的过程中,不断将 往右移,不改变 的值,直到发现 (此时的 就相当于原来的 ),完成一次匹配。
这样我们只会从 转移到 ,可以使用滚动数组优化。具体的转移可以参考代码。其中的一个细节是,若发现 ,我们只能将 更新,但是此时 ,因此我们完成匹配时判断的是 和 是否相等。
::::info[AC 代码] Submission
#include <bits/stdc++.h> using namespace std; int n, m, a[16000], b[16000], nxta[16000], nxtb[16000], pre[16000][2], dp[16000][2], nxt[16000][2]; map<int, int> mp; int main() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= m; i++) cin >> b[i]; for (int i = m; i >= 1; i--) { if (mp[b[i]]) nxtb[i] = mp[b[i]]; mp[b[i]] = i; } for (int i = 0; i <= m; i++) pre[i][1] = -0x3f3f3f3f; for (int i = 0; i <= n; i++) { for (int j = 0; j <= m; j++) dp[j][0] = dp[j][1] = -0x3f3f3f3f; for (int j = 0; j <= m; j++) { pre[j + 1][0] = max(pre[j + 1][0], pre[j][0]); dp[j][0] = max(dp[j][0], pre[j][0]); if (a[i + 1] == b[j + 1] && nxtb[j + 1]) dp[nxtb[j + 1]][1] = max(dp[nxtb[j + 1]][1], pre[j][0]); if (a[i + 1] == b[j]) dp[j][0] = max(dp[j][0], pre[j][1] + 2); else dp[j][1] = max(dp[j][1], pre[j][1]); } for (int j = 0; j <= m; j++) pre[j][0] = dp[j][0], pre[j][1] = dp[j][1]; } cout << max(pre[m][0], pre[m][1]); return 0; }::::
- 1
信息
- ID
- 5761
- 时间
- 3000ms
- 内存
- 132MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者