• 【CodeForces】CF10D LCIS


    题目地址:

    https://www.luogu.com.cn/problem/CF10D

    题面翻译:
    求两个串的最长公共上升子序列。

    题目描述:
    This problem differs from one which was on the online contest.

    The sequence a 1 , a 2 , . . . , a n a_{1},a_{2},...,a_{n} a1,a2,...,an is called increasing, if a i < a i + 1 a_{i}ai<ai+1 for i < n ii<n .

    The sequence s 1 , s 2 , . . . , s k s_{1},s_{2},...,s_{k} s1,s2,...,sk is called the subsequence of the sequence a 1 , a 2 , . . . , a n a_{1},a_{2},...,a_{n} a1,a2,...,an , if there exist such a set of indexes 1 ≤ i 1 < i 2 < . . . < i k ≤ n 1\le i_{1}1i1<i2<...<ikn that a i j = s j a_{i_j}=s_{j} aij=sj . In other words, the sequence s s s can be derived from the sequence a a a by crossing out some elements.

    You are given two sequences of integer numbers. You are to find their longest common increasing subsequence, i.e. an increasing sequence of maximum length that is the subsequence of both sequences.

    输入格式:
    The first line contains an integer n n n ( 1 ≤ n ≤ 500 1\le n\le 500 1n500 ) — the length of the first sequence. The second line contains n n n space-separated integers from the range [ 0 , 1 0 9 ] [0,10^{9}] [0,109] — elements of the first sequence. The third line contains an integer m m m ( 1 ≤ m ≤ 500 1\le m\le 500 1m500 ) — the length of the second sequence. The fourth line contains m m m space-separated integers from the range [ 0 , 1 0 9 ] [0,10^{9}] [0,109] — elements of the second sequence.

    输出格式:
    In the first line output k k k — the length of the longest common increasing subsequence. In the second line output the subsequence itself. Separate the elements with a space. If there are several solutions, output any.

    思路是动态规划。求最长公共子序列长度,可以参考https://blog.csdn.net/qq_46105170/article/details/114242851。设两个序列分别为 a a a b b b,设 f [ i ] [ j ] f[i][j] f[i][j] a [ 1 : i ] a[1:i] a[1:i] b [ 1 : j ] b[1:j] b[1:j]的最长公共上升子序列的长度,并且要求该子序列含 b [ j ] b[j] b[j]。则: f [ i ] [ j ] = max ⁡ { f [ i − 1 ] [ j ] , 1 + max ⁡ k < j ∧ b [ k ] < a [ i ] f [ i − 1 ] [ k ] } f[i][j]=\max\{f[i-1][j],1+\max_{kf[i][j]=max{f[i1][j],1+k<jb[k]<a[i]maxf[i1][k]}当不含 a [ i ] a[i] a[i]时,最长公共上升子序列长度即为 f [ i − 1 ] [ j ] f[i-1][j] f[i1][j];当含 a [ i ] a[i] a[i]的时候,隐含 a [ i ] = b [ j ] a[i]=b[j] a[i]=b[j],可以以倒数第二个数是哪个来分类,如果不含倒数第二个数,则长度为 1 1 1;如果倒数第二个数是 b [ k ] , k < j b[k],kb[k],k<j,隐含 b [ k ] < b [ j ] = a [ i ] b[k]b[k]<b[j]=a[i],则长度为 f [ i − 1 ] [ k ] + 1 f[i-1][k]+1 f[i1][k]+1。所以不含 a [ i ] a[i] a[i]时,最长长度为 1 + max ⁡ k < j ∧ b [ k ] < a [ i ] { f [ i − 1 ] [ k ] } 1+\max_{k1+maxk<jb[k]<a[i]{f[i1][k]}。我们可以将 i i i 1 ∼ n 1\sim n 1n遍历,将 j j j 1 ∼ m 1\sim m 1m遍历,同时用一个变量 p p p使得 p < j ∧ b [ k ] < a [ i ] pp<jb[k]<a[i]并且 f [ i − 1 ] [ p ] f[i-1][p] f[i1][p]取到最大值。这样在内层循环里只需要常数的时间更新 f [ i ] [ j ] f[i][j] f[i][j],同时只需要注意更新 p p p即可。最后答案就是 max ⁡ j f [ n ] [ j ] \max_j f[n][j] maxjf[n][j]。为了求具体序列,我们用一个二维数组 g [ i ] [ j ] g[i][j] g[i][j]表示使得 f [ i ] [ j ] f[i][j] f[i][j]取得最大值的时候,倒数第二个数在 b b b中的下标(如果不存在倒数第二个数,则赋值为 0 0 0)。那么要求具体序列,只需要找到使得 f [ n ] [ p ] f[n][p] f[n][p]最大的那个 p p p,接着用 g [ n ] [ p ] g[n][p] g[n][p]替代 p p p不停向前递推即可。代码如下:

    #include 
    using namespace std;
    
    const int N = 510;
    int n, m;
    int a[N], b[N];
    int f[N][N], pre[N][N];
    
    int main() {
      scanf("%d", &n);
      for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
      scanf("%d", &m);
      for (int i = 1; i <= m; i++) scanf("%d", &b[i]);
    
      for (int i = 1; i <= n; i++)
        for (int j = 1, p = 0; j <= m; j++) {
          f[i][j] = f[i - 1][j];
          pre[i][j] = pre[i - 1][j];
          if (a[i] == b[j] && f[i - 1][p] + 1 > f[i][j]) {
            f[i][j] = f[i - 1][p] + 1;
            pre[i][j] = p;
          }
          if (b[j] < a[i] && f[i - 1][j] > f[i - 1][p])
            p = j;
        }
    
      int res = 0, p;
      for (int i = 1; i <= m; i++)
        if (res < f[n][i]) {
          res = f[n][i];
          p = i;
        }
    
      printf("%d\n", res);
    
      m = res;
      while (p) {
        a[m--] = b[p];
        p = pre[n][p];
      }
    
      for (int i = 1; i <= res; i++) printf("%d ", a[i]);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    时空复杂度 O ( n m ) O(nm) O(nm)

  • 相关阅读:
    基于邻接矩阵的深度优先算法和广度优先算法
    java LevelDB工具类
    《数据结构》之栈和堆结构及JVM简析
    【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装
    打家劫舍3(二叉树型)Java
    基于SpringBoot的大学城水电管理系统
    awvs 中低危漏洞
    Cookie的常用方法(javaWeb)
    wxpython设计GUI:窗口Frame最大化、最小化、关闭及全屏显示的说明
    apollo自动驾驶进阶学习之:在apollo中模拟障碍物的三种方法
  • 原文地址:https://blog.csdn.net/qq_46105170/article/details/126403922