LCS与LIS的同质性
此段无比伟大而清晰的解释来自阮行止。我仅调整了B序列的顺序,使之最初不为顺序序列(因为我的代码实现在这里栽了跟斗orz)。
关于(LCS)为什么可以转化成LIS问题,这里提供一个解释。
比如这样的两个序列:
A:3 2 1 4 5
B:2 5 4 1 3
我们不妨给它重新编个号,使得A的逆序为0,即3-a(3标成a),2-b,1-c,4-d,5-e。于是成为:
A: a b c d e
B: b e d c a
这样标号后,LCS长度显然不会因此改变,毕竟没有对原有序列进行任何相对位置的改变。
于是有如下三段论推理
- A本身是单调递增的,A的任意子序列单调。
- 两个序列的公共子序列,一定是A的子序列。
- 因此这个子序列也是单调递增的。
换句话说:我们将共用关系,转化成了重新编号规则下的单调递增关系!
那么现在,为了在B中寻找与A的共用片段,只需要在B中任取(因为2个序列相同数组的排列)递增的子序列即可。
最长的递增子序列是什么问题呢?
你猜对了小朋友,是LIS(doge
LCS模板
#include <bits/stdc++.h>
using namespace std;
const int N = 100001;
int n, m[N], mp[N], k[N], r[N], p = 1, ans;
int main()
{
cin >> n;
//通过映射,将LCS转化为LIS问题
for (int i = 1; i <= n; i++)
cin >> m[i], mp[m[i]] = i;
for (int i = 1; i <= n; i++)
cin >> k[i], k[i] = mp[k[i]];
//nlogn的LIS算法
r[0] = k[1];//事先考虑初始特例,使得分支简化
for (int i = 2; i <= n; i++)
{
auto it = upper_bound(r, r+p, k[i]);
if (it == r+p) r[p++] = k[i];
else *it = k[i];
}
cout << p;
}
LIS模板
关于LIS,这里是一个简略写法。如果原序列不限制相同,会出现危险的全同情况。于是我们可以有:
#include <bits/stdc++.h>
using namespace std;
int r[1005], p, tmp;
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> tmp;
auto it = upper_bound(r, r + p, tmp);
if (it == r + p)//搜到末端
if (*(it-1) < tmp || p == 0)//如果不全同,或者为初态特例
dp[ptr++] = tmp;
else continue;//这个表示全同。不能加到上升序列当中。
else *it = tmp;
}
cout << ptr << endl;
}