【洛谷绿题】LCS与LIS的巧妙转换

P1439 【模板】最长公共子序列

 

使用常规的LCS思路(也就是动态规划),时间复杂度o(n^2),数据太大,肯定会TLE(如果数据不大,也不会是绿题了),再次读题,发现题目中多给了一个条件,序列是n的一个全排列,那么两个序列所包含的数字都是一样的,只是排列顺序不一样。

那么就有一个十分巧妙的处理方法,利用map,建立映射,以A序列(3 2 1 4 5)为基准,即3-a,2-b,1-c,4-d,5-e,那么A序列就变为(a b c d e),是一个上升序列,B序列就变为(c b a d e),A,B的公共最长子列长度肯定不变,而这时有了有趣的性质:A,B的公共子列必是A的子列,而A是上升的,因此问题就转化为求序列B的最长上升子列问题(LIS)问题。

3 2 1 4 5

a b c d e

c b a d e

1 2 3 4 5

但考虑到数据量太大的问题n^2的复杂度并不好,不采用动态规划的方法,而是使用一个辅助数组d[i],来实时保存最长上升子列的长度,将B序列扫一遍,最终d数组的长度就是答案,复杂度为nlogn,就能AC啦。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
#define int long long
#define x(i) x+dirx[i]
#define y(i) y+diry[i]
int a[N],b[N],n,d[N];
map<int,int> s;
int LIS()
{
	int len=0;
	for(int i=1;i<=n;i++)
	{
		if(b[i]>d[len]) d[++len]=b[i];
		else
		{
			int it=lower_bound(d,d+len,b[i])-d;
			d[it]=b[i];
		}
	}
	return len;
}
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) 
	{
		cin>>a[i];
		s[a[i]]=i;
		a[i]=i;
	}
    for(int i=1;i<=n;i++) 
	{
		cin>>b[i];
		b[i]=s[b[i]];
	}
	//转化为求序列b的最长上升子列问题
	cout<<LIS()<<"\n"; 
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值