题解【AcWing272】最长公共上升子序列
2024-10-08 07:42:52
一道线性 DP 好题。
设 \(dp_{i,j}\) 表示在所有 \(a_{1\dots i}\),\(b_{1\dots j}\) 的子序列中,以 \(b_j\) 结尾的最长公共上升子序列的最大长度。
转移的时候考虑 \(2\) 种情况:
- 若不选择 \(a_i\),则 \(dp_{i,j}=dp_{i-1,j}\);
- 若选择 \(a_i\),则 \(dp_{i,j} = \max_{1\leq k \leq j,b_k < b_j}\{dp_{i-1,k}\}+1\)。又因为有 \(a_i=b_j\),所以 \(dp_{i,j} = \max_{1\leq k \leq j,b_k < a_i}\{dp_{i-1,k}\}+1\)。
转移的代码:
for (int i = 1; i <= n; i+=1)
for (int j = 1; j <= n; j+=1)
{
dp[i][j] = dp[i - 1][j];
if (a[i] == b[j])
{
int maxdp = 0;
for (int k = 1; k < j; k+=1)
if (b[k] < a[i])
maxdp = max(maxdp, dp[i - 1][k]);
dp[i][j] = max(dp[i][j], maxdp + 1);
}
}
这样转移的复杂度其实是 \(O(n^3)\) 的,明显会超时。
于是我们考虑优化,即对转移的代码进行等价变形。
我们发现,第三重循环能够转移的状态其实是所有 小于 \(j\) 的 \(k\),且 \(b_k < a_i\)。因为 \(a_i\) 的值是不变的,所以我们可以预处理出所有 \(dp_{i,k}(k<j)\) 的最大值,即 \(dp_{i,j}\) 的前缀最大值。
具体做法就是将变量 maxdp 移到第二层循环外,然后如果 \(b_j < a_i\) 就将 maxdp 与 \(dp_{i,j}\) 取 \(\max\)。
完整代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 3003;
int n, m;
int a[N], b[N], dp[N][N];
int main()
{
cin >> n;
for (int i = 1; i <= n; i+=1)
cin >> a[i];
for (int i = 1; i <= n; i+=1)
cin >> b[i];
for (int i = 1; i <= n; i+=1)
{
int maxdp = 0;
for (int j = 1; j <= n; j+=1)
{
dp[i][j] = dp[i - 1][j];
if (a[i] == b[j]) dp[i][j] = max(dp[i][j], maxdp + 1); //转移
if (b[j] < a[i]) maxdp = max(maxdp, dp[i][j]); //前缀最大值
}
}
int ans = 1;
for (int i = 1; i <= n; i+=1) ans = max(ans, dp[n][i]);
cout << ans << endl;
return 0;
}
最新文章
- 我的MYSQL学习心得(五) 运算符
- Object-C中一些不同于C系列语言表现的特性
- 好文EF
- hdu 1281 棋盘游戏
- [转]C#中yield用法
- 漏网之鱼--HTML&;CSS
- 【DOORS】如何基于DOORS实施需求管理
- Java IO详解(六)------随机访问文件流
- react入门(一)
- C#设计模式(5)——建造者模式
- python中字符串前的r什么意思
- 执行webpack-dev-server时,提示端口被占用。
- 关于一个div上下左右居中的css方法
- .pages怎么在windows上打开?Windows下打开在Mac中编辑的.pages文件方法
- freemarker【FTL】常见语法大全
- 安全测试工具之Burpsuite
- angular controller 之间的通信方式
- python使用selenium、PhantomJS获得网站cookie信息#windows
- Jmeter----HTTP Request Defaults
- Java基础教程:IO流与文件基础