P1439 【模板】最长公共子序列(LCS+LIS)

Part1:题目链接

点我就送屠龙宝刀[doge]

Part2:题目

在这里插入图片描述

Part3:思路

突然高产,实则心无波澜,甚至还能再更一篇出来。

在这里插入图片描述
如果只看题目的话,这道题就是1000%的LCS(Longest Common Sequence,最长公共子序列)

题目中50%的数据是可以通过LCS( O(n^2) )拿分的,但这显然不是我们的目标。
有关于LCS的代码实现,本篇博客不再过多说明,我们主要来说一下如何在这道题拿1000%的分数。

首先我们需要注意一个点:

关键1:关于这两个序列,它们是不同顺序的同数据序列。

这个点很重要,它将是我们解决这道题的关键。

接下来,引入第二个关键点:
我们假设序列1是严格递增的,这里所说的严格递增并不是实际意义上的递增。

比如序列1为1 2 5 3 4,我们认为5就是比3小,4就是这五个数最大的。
此时序列1为严格递增的。

那么对于序列1来说,序列2是我的一个排列组合,如果序列2要和我重合,那么重合部分的大小规则必须和我一致。

也就是说,

关键2:序列2和序列1的LCS长度,就是在序列2严格遵守序列1的排序规则下所能产生的LIS的长度。

如果你领悟了以上两点,那么这道题就非常简单了。
建议不懂的再仔细想想,结合样例去理解。
先想一下这个样例:

123456
321546

再带入博客中所说的两个关键点,想一下这个样例:

315264
135264

接下来就只是枯燥的代码环节了。
由小卷子为大家奉上代码。

在这里插入图片描述

Part4:AC代码

#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;

int a[maxn],b[maxn];
int dp[maxn],num[maxn];

int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],num[a[i]]=i;
    ///寻找自己在对方的位置,相当于遵守对方的排序规则
    for(int i=1;i<=n;i++) cin>>b[i],b[i]=num[b[i]];
    dp[1]=b[1];
    int len=1;
    ///nlogn的LIS
    for(int i=2;i<=n;i++)
    {
        if(b[i]>dp[len]) dp[++len]=b[i];
        else
        {
            int pos=lower_bound(dp+1,dp+1+len,b[i])-dp;
            dp[pos]=b[i];
        }
    }
    //for(int i=1;i<=len;i++) cout<<dp[i]<<" ";
    cout<<len<<endl;
}

/*7 6 3 9 8 5 4 1 2

1 2 3 4 5 6 7 8 9
8 9 3 7 6 2 1 5 4*/

一开始自己也是没想懂,后来看到了一些东西,被启发了。
也感谢漂亮学姐的提问,使得我思路更加清楚了,于是满腔热血的写了下来。

Part5:死宅时间

取自《银魂》13集

坂田银时:
“人的一生,就仿佛身负沉重行李走在遥远的旅程上。”
这句话,是以前一个叫德川田信秀的大叔说的。
初听觉得是句很烦人的话,可是慢慢想想,老人家的话果然还是有道理啊。
也许算不上什么行李,不过任何人的双臂中都抱着些珍贵的东西。
但拥有的时候永远不会留意到,注意到那份沉重却是在一切都从手中悄然滑落了的时候。
不知道多少次的反复想着,那种玩意儿再也不要拥有了。
可是,不知道什么时候又背起了。 也许索性全部抛弃会比较轻松,可无论如何还是不想那样做。
因为没有那些家伙的话,旅程将多么无趣啊。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值