• 【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)

  • 相关阅读:
    Leetcode160. 相交链表(双指针)
    stm32编写Modbus步骤
    循环结构 ----- for/in 语句 与 for/of语句
    libevent源码学习笔记
    深度学习训练营之彩色图片分类
    SpringBoot 日志
    手记:把代码上传到Gitee等远程仓库的过程记录及常见问题
    开发中常用Linux命令总结
    python --Matplotlib详解
    矩阵分析与应用+张贤达
  • 原文地址:https://blog.csdn.net/qq_46105170/article/details/126403922