奇技淫巧训练之二
https://www.luogu.org/problem/P1439
看到标题你肯定会想什么狗屁奇技淫巧,不就是个模板题吗
然后乍一看数据范围,是不是觉得很方?
本题的关键在于它还给出了一个条件,
那就是这两个序列都是排列
就是说不会有元素重复!!!(突破口应该放在这里)
而且两序列的元素排序后是相等的
问题转化为求最长上升子序列问题
CS转LIS条件也确实很简单:一个数组先用编号i来映射a[i],再通过这种映射关系转换b[i],从而使b[i]有序,通过LIS可得出结论。
我这样一讲觉得一定很多人都会云里雾里,一脸蒙蔽,因为我这种蒟蒻第一眼也没理解。这时候就要
手动模拟一组数据来边观察变分析了!
我们取
8
3 7 8 5 6 4 1 2
8 2 4 3 6 5 7 1
答案是 3(3,5,1或3,7,1等)
因为LCS要控制对应数字相同,顺序相同,两个变量不确定时候我们就控制一个,因为这是1n的全排列,数字虽然确定是1n但却不对应,那么当然想到用map这种映射的方法,把a[i]与b[i]每一个数字都通过同一个映射关系对应,就能控制了数字相同:
a[i] a1[i]
3- 1
7- 2
8- 3
5- 4
6- 5
4- 6
1- 7
2- 8
现在a[i]与a1[i]已经通过确立了一个映射关系变得有序了(什么是映射关系?3对应1,7对应2,8对应3……这就是我们这题确立的对应关系,具体有什么用待会讲到),我们再把b[i]与b1[i]用这种关系建立起来:
b[i] b1[i]
8- 3
2- 8
4- 6
3- 1
6- 5
5- 4
7- 2
1- 7
你看,既然a[i]和b[i]用了同一种映射关系变成了a1[i]和b1[i],那么:
只需求出a1[i]和b1[i]的LCS不就可以了吗OwO?
由于映射关系相同,变化出来的新数组已经控制了数字的相等,现在只要顺序都是不下降的就好了。又因为已经控制了a1[i]是升序(现在知道为啥映射关系控制是他的编号对应了吧),所以:
就是求b1[i]的最长不下降子序列!
对于3 8 6 1 5 4 2 7,用LIS走一遍就好了。
这就是LCS转LIS的思路全过程,所以说搞不懂的题手动摸一个数据就可以方便理解的。
code by std:(码风比较怪异不是我写的)
#include <iostream>
#include<algorithm>
using namespace std;
struct node{
int a;
int b;
}a[200000];
int n,ans,t[200000],f[100000],ha[100000];
int find(int a)
{
int k=a,p=0;
while (k>0){
p=max(p,t[k]);
k-=(-k)&k;
}
return p;
}
void update(int a,int p)
{
int k=a;
while (k<=100000){
t[k]=max(t[k],p);
k+=(-k)&k;
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].a,ha[a[i].a]=i;
for (int i=1;i<=n;i++) cin>>a[i].b;
for (int i=1;i<=n;i++) a[i].b=ha[a[i].b]; //核心转换语句
for (int i=1;i<=n;i++)
{
f[i]=find(a[i].b)+1;
update(a[i].b+1,f[i]);
ans=max(ans,f[i]);
}
cout<<ans<<endl;
return 0;
}