奇技淫巧训练之二

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;
}
posted @ 2019-10-05 11:35  wzx_believer  阅读(99)  评论(0编辑  收藏  举报