难度
普 及 + / 提 高 \color{green}普及+/提高 普及+/提高
洛谷模板题
题意
给两个 N N N 的全排列 P A P_A PA 和 P B P_B PB
求两个全排列的 最长公共子序列(Longest Common Subsequence) 的长度。
数据范围
N ≤ 1 0 5 N\le 10^5 N≤105
思路
- 若普通的动态规划这么一做,明显是 O ( N 2 ) O(N^2) O(N2) 的,时间空间都炸掉。
- 我们需要使用: L C S LCS LCS转 L I S LIS LIS大法!
- 对 P A P_A PA 向 P B P_B PB 进行映射后,对每个位置的元素的对应下标进行倒序记录(见上绿色部分)。若找不到则为空集。
- 把所有记录储存成一个数组 S S S ,则数组 S S S 为:[4,2,5,3,1,4,2]
- 接下来,我们对 S S S进行LIS。所得到的结果即为原LCS的答案。(证明易得略)。
- L I S LIS LIS的时间复杂度为严格 O ( N log N ) O(N\log N) O(NlogN)
- 但是在某些极端情况(比如两个原数组都是充满一个字母‘A’),会退化到 O ( N 2 log N ) O(N^2\log N) O(N2logN)
- 但是这题的所有元素位置的映射只有一个,因此不会产生这种退化。
核心代码
时间复杂度 O ( N log N ) O(N\log N) O(NlogN)
/*
_ __ __ _ _
| | \ \ / / | | (_)
| |__ _ _ \ V /__ _ _ __ | | ___ _
| '_ \| | | | \ // _` | '_ \| | / _ \ |
| |_) | |_| | | | (_| | | | | |___| __/ |
|_.__/ \__, | \_/\__,_|_| |_\_____/\___|_|
__/ |
|___/
*/
const int MAX = 1e5+50;
const int INF = 0x3f3f3f3f;
int pos[MAX];
int aa[MAX];
int dp[MAX];
int main()
{
int n;scanf("%d",&n);
for(int i = 1;i <= n;++i){
int t;scanf("%d",&t);
pos[t] = i;
}
fill(dp,dp+MAX,INF);
for(int i = 1;i <= n;++i){
int t;scanf("%d",&t);
aa[i] = pos[t];
int p = lower_bound(dp,dp+MAX,aa[i]) - dp;
dp[p] = aa[i];
}
int ans = 0;
for(int j = 0;j < MAX;++j){
if(dp[j] == INF){
cout << j;
break;
}
}
return 0;
}