首页 > 其他分享 >洛谷题单指南-动态规划2-P1439 【模板】最长公共子序列

洛谷题单指南-动态规划2-P1439 【模板】最长公共子序列

时间:2024-04-26 11:15:47浏览次数:32  
标签:P1439 int 洛谷题 mid 模板 公共 序列 最长 dp

原题链接:https://www.luogu.com.cn/problem/P1439

题意解读:求最长公共子序列的长度。

解题思路:

1、O(n^2)的方法:动态规划

设两个排列为a,b

设dp[i][j]表示a[1~i]与b[1~j]的最长公共子序列长度

根据公共子序列结尾是否包含a[i]、b[j]是否相等分情况讨论:

如果a[i] == b[j]

  则结尾包含a[i]和b[j],所以dp[i][j] = dp[i-1][j-1] + 1,即a[1~i]与b[1~j]的最长公共子序列等同于a[1~i-1]与b[1~j-1]的最长公共子序列再加上1

如果a[i] != b[j]

  则结尾不包含a[i]或者不包含b[j]

  • 不包含a[i]:所以dp[i][j] = dp[i-1][j],即a[1~i]与b[1~j]的最长公共子序列等同于a[1~i-1]与b[1~j]的最长公共子序列
  • 不包含b[j]:所以dp[i][j] = dp[i][j-1],即a[1~i]与b[1~j]的最长公共子序列等同于a[1~i]与b[1~j-1]的最长公共子序列

对以上情况求max即可。

由于空间和时间复杂度都是O(n^2),因此只能处理n=1000的情况。

50分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1005; //注意不能写100005,提交后数组内存超出限制,编译失败,但本地看不出来
int a[N], b[N];
int dp[N][N];
int n;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) cin >> b[i];

    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            if(a[i] == b[j]) dp[i][j] = max(dp[i][j], dp[i-1][j-1] + 1);
        }
    }
    cout << dp[n][n];

    return 0;
}

2、O(logn)的方法:LIS+二分

由于两个排列a、b都是1~n组成,只是顺序不同

举个例子:a = {3, 2, 1, 4, 5},b = {1, 2, 3, 4, 5}

用一个桶数组h[]保存a中每个元素的位置:

h[3] = 1, h[2] = 2, h[1] = 3, h[4] = 4, h[5] = 5

再定义一个数组c用来表示b数组每个元素在a数组中的位置:

c = {3, 2, 1, 4, 5}

由于a中每个元素的下标是递增的,所以如果b中元素对应的a的位置是递增(也就是c中元素递增),那么可以认为和a是公共子序列

因此问题转换为:计算c中最长上升子序列的长度

要实现O(logn)的算法,可以采用此文介绍的单调栈+二分的方式进行优化。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
int a[N], b[N], h[N], c[N];
int s[N], top;
int n;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        h[a[i]] = i;
    } 
    for(int i = 1; i <= n; i++)
    {
        cin >> b[i];
        c[i] = h[b[i]];
    } 

    for(int i = 1; i <= n; i++)
    {
        if(top == 0 || s[top] < c[i]) s[++top] = c[i];
        else
        {
            int l = 1, r = top, ans = -1;
            while(l <= r)
            {
                int mid = (l + r) >> 1;
                if(s[mid] >= c[i])
                {
                    ans = mid;
                    r = mid - 1;
                }
                else l = mid + 1;
            }
            s[ans] = c[i];
        }
    }
    cout << top;

    return 0;
}

 

标签:P1439,int,洛谷题,mid,模板,公共,序列,最长,dp
From: https://www.cnblogs.com/jcwy/p/18159553

相关文章

  • Ubuntu 24.04 LTS x86_64 OVF (sysin) - VMware 虚拟机模板
    Ubuntu24.04LTSx86_64OVF(sysin)-VMware虚拟机模板Ubuntu24.04LTS(GNU/Linux6.8-genericx86_64)请访问原文链接:Ubuntu24.04LTSx86_64OVF(sysin)-VMware虚拟机模板,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org无耻抄袭者YuTao请远离本站!!!......
  • 洛谷题解-官方题单-递归与递推
    P1255数楼梯原题链接题目描述楼梯有N阶,上楼可以一步上一阶,也可以一步上二阶。编一个程序,计算共有多少种不同的走法。对于60%的数据,N≤50;对于100%的数据,1≤N≤5000。思路:每次有2种方法上楼梯,要么上一阶,要么上二阶。第一种:得50分的做法是可以用递归来解:点击查看代码......
  • 类模板的常见用法
    class_template类模板和函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。类模板用于实现类所需数据的类型参数化template<classNameType,classAgeType>classPerson{public: Person(NameTypename,AgeTypeage) { ......
  • [题解]P5656 【模板】二元一次不定方程 (exgcd)
    P5656【模板】二元一次不定方程(exgcd)若存在\(ax+by=c\),则可以根据特解\(x,y\)求出任意通解\(x',y'\):\(\begin{cases}x'=x+k*\frac{b}{\gcd(a,b)}\\y'=y-k*\frac{a}{\gcd(a,b)}\end{cases}(k\in\mathbb{Z})\)求特解的方法是「扩展欧几里得(exgcd)」,如果没接触过可以先阅读......
  • 洛谷题单指南-动态规划2-P2758 编辑距离
    原题链接:https://www.luogu.com.cn/problem/P2758题意解读:对a字符串最少操作几次可以变成b字符串,看似无从下手,可以从内部递推关系着手。解题思路:设dp[i][j]表示将a字符串1~i变成b字符串1~j的最少操作次数,字符串下标从1开始。如何思考递推?可以从最后一步为切入点!最后一步对a[i]......
  • wpf DataTemplate 动态模板内容
     <DataGridTemplateColumnWidth="50"Header="选择">              <DataGridTemplateColumn.CellTemplate>                <DataTemplate>                       ......
  • 洛谷题单指南-动态规划2-P1874 快速求和
    原题链接:https://www.luogu.com.cn/problem/P1874题意解读:一个数字字符串s,分解成几个整数,和为n,计算最少加号个数,也就是计算最少分解的整数个数-1。解题思路:此题虽然分类在动态规划,但数据量不大,DFS更加直观和易于理解,所以采用DFS暴搜+剪枝来解决。搜索思路是对数字字符串依次枚......
  • phpcms pc:get 标签用法;phpcms模板中使用PHP标签
     注意:变量 $catid 需要是从控制器里解析出来的<divclass="show-right-top"><divclass="sch-recruit-right-title"><p><imgsrc="/statics/boot/images/quan3.png">快速链接</p></div>......
  • 洛谷题单指南-动态规划2-P4933 大师
    原题链接:https://www.luogu.com.cn/problem/P4933题意解读:求有多少个子序列可以组成等差序列解题思路:1、暴力DFS如果实在想不出动规的方法,对于n<=20的数据,可以DFS枚举所有子序列的子集,再判断是否是等差数列。30分代码:#include<bits/stdc++.h>usingnamespacestd;const......
  • [题解]P5431 【模板】模意义下的乘法逆元 2
    可恶,卡常好难受。P5431【模板】模意义下的乘法逆元2将分数通分,第\(i\)个分数是\(\frac{k^i*fac\diva[i]}{fac}\),\(fac\)表示所有元素的积。我们可以用\(lr,rl\)记录\(a\)的前缀后缀积,第\(i\)个分数就是\(\frac{k^i*lr[i-1]*rl[i+1]}{lr[n]}\)。这样分母都是\(lr[n]\),分子就......