2025-10-19 hetao1733837刷题记录
LG2516 [HAOI2010] 最长公共子序列
原题链接:P2516 [HAOI2010] 最长公共子序列 - 洛谷
分析:是常见的LCS的dp求解问题。我们设dp1[i][j]表示A[1~i]与B[1~j]的LCS长度。
考虑转移,
OK,但是,这题还额外让我们统计LCS的个数,怎么办?
我们设dp2[i][j]表示A[1~i]与B[1~j]不同LCS的个数。
考虑转移,
初始化,
代码:
#include <bits/stdc++.h>
#define mod 100000000
using namespace std;
const int N = 5005;
int dp1[N][N], dp2[N][N]; //dp1统计LCS长度,dp2统计LCS个数
char a[N], b[N];//不敢用变量名y
string s;
int main(){int n = 0, k = 0;cin >> s;for (int i = 0; i < s.size() - 1; i++)a[++n] = s[i];cin >> s;for (int i = 0; i < s.size() - 1; i++)b[++k] = s[i];for (int i = 1; i <= n; i++){for (int j = 1; j <= k; j++){if (a[i] == b[j])dp1[i][j] = dp1[i - 1][j - 1] + 1;elsedp1[i][j] = max(dp1[i - 1][j], dp1[i][j - 1]);}}for (int i = 0; i <= n; i++)dp2[i][0] = 1;for (int j = 0; j <= k; j++)dp2[0][j] = 1;for (int i = 1; i <= n; i++){for (int j = 1; j <= k; j++){if (a[i] == b[j])dp2[i][j] = 1ll * (dp2[i][j] + dp2[i - 1][j - 1]) % mod;if (dp1[i][j] == dp1[i - 1][j])dp2[i][j] = 1ll * (dp2[i][j] + dp2[i - 1][j]) % mod;if (dp1[i][j] == dp1[i][j - 1])dp2[i][j] = 1ll * (dp2[i][j] + dp2[i][j - 1]) % mod;if (dp1[i][j] == dp1[i - 1][j - 1] && a[i] != b[j])dp2[i][j] = 1ll * (dp2[i][j] - dp2[i - 1][j - 1] + mod) % mod;}}cout << dp1[n][k] << '\n';cout << dp2[n][k];
}
咦,发现MLE了,嘻嘻,开两个5005*5005的二维数组当然会MLE,怎么办呢?
发现转移只会从上一个转下来,滚动数组滚一下就行了。
正解:
#include <bits/stdc++.h>
#define mod 100000000
using namespace std;
const int N = 5005;
int dp1_now[N], dp1_lst[N], dp2_now[N], dp2_lst[N];
char a[N], b[N];
string s;
int main(){int n = 0, k = 0;cin >> s;for (int i = 0; i < s.size() - 1; i++)a[++n] = s[i];cin >> s;for (int i = 0; i < s.size() - 1; i++)b[++k] = s[i];for (int j = 0; j <= k; j++){dp2_lst[j] = 1;}for (int i = 1; i <= n; i++){dp2_now[0] = 1;for (int j = 1; j <= k; j++){if (a[i] == b[j]){dp1_now[j] = dp1_lst[j - 1] + 1;} else{dp1_now[j] = max(dp1_lst[j], dp1_now[j - 1]);}dp2_now[j] = 0;if (a[i] == b[j]){dp2_now[j] = (dp2_now[j] + dp2_lst[j - 1]) % mod;}if (dp1_now[j] == dp1_lst[j]){dp2_now[j] = (dp2_now[j] + dp2_lst[j]) % mod;}if (dp1_now[j] == dp1_now[j - 1]){dp2_now[j] = (dp2_now[j] + dp2_now[j - 1]) % mod;}if (a[i] != b[j] && dp1_now[j] == dp1_lst[j - 1]){dp2_now[j] = (dp2_now[j] - dp2_lst[j - 1] + mod) % mod;}}swap(dp1_now, dp1_lst);swap(dp2_now, dp2_lst);}cout << dp1_lst[k] << '\n';cout << dp2_lst[k];return 0;
}
这里我们重新设了dp方程,详细如下:
dp1_lst[j] = dp1[i - 1][j]
dp1_now[j] = dp1[i][j]
dp2_lst[j]=dp2[i-1][j]
dp2_now[j]=dp2[i][j]
转移与原来保持一致。