[模板] LIS(最长上升子序列)和 LCS(最长公共子序列)

10 篇文章 0 订阅
8 篇文章 0 订阅

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长度显然不会因此改变,毕竟没有对原有序列进行任何相对位置的改变。
于是有如下三段论推理

  1. A本身是单调递增的,A的任意子序列单调。
  2. 两个序列的公共子序列,一定是A的子序列。
  3. 因此这个子序列也是单调递增的。

换句话说:我们将共用关系,转化成了重新编号规则下的单调递增关系!

那么现在,为了在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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值