1. 程式人生 > 其它 >SpringBoot學習(一)@Configuration

SpringBoot學習(一)@Configuration

傳送門

題目描述

給出 \(1,2,\ldots,n\) 的兩個排列 \(P_1\)\(P_2\),求它們的最長公共子序列。

輸入格式

第一行是一個數 \(n\)

接下來兩行,每行為 \(n\) 個數,為自然數 \(1,2,\ldots,n\) 的一個排列。

輸出格式

一個數,即最長公共子序列的長度。

輸入輸出樣例

輸入 #1

5 
3 2 1 4 5
1 2 3 4 5

輸出 #1

3

說明/提示

  • 對於 \(50%\) 的資料, \(n \le 10^3\)

  • 對於 \(100%\) 的資料,\(n \le 10^5\)


50tps

50分的做法就是LCS [1] 的模板了。

比如求a陣列和b陣列的LCS:

\(dp[i][j]\)為a的前\(i\)位和b的前\(j\)位的LCS的長度。

狀態轉移方程很好想出來,即:

a[i] == b[j]時,就說明a[i]和b[j]相等了,既然a[i]和b[j]相等了,那這個狀態肯定與dp[i-1][j-1]這個情況有關係,所以這個情況狀態的狀態轉移方程是\(dp[i - 1][j - 1] + 1\)
其他情況,即無法更新公共元素,考慮繼承已經算過的:

\(dp[i][j]=max(dp[i−1][j],dp[i][j−1])\)

程式碼:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 1005
int a[MAXN], b[MAXN];
int dp[MAXN][MAXN];
int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for(int i = 1; i <= n; i++)
        scanf("%d", &b[i]);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(a[i] == b[j])
                dp[i][j] = dp[i - 1][j - 1] + 1;
            else
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        }
    }
    printf("%d\n", dp[n][n]);
    return 0;
}

親測50tps


所以我們得加優化。

再來認真讀讀題:

給出 \(1,2,\ldots,n\) 的兩個排列 \(P_1\)\(P_2\),求它們的最長公共子序列。

排列的意思就是指\(P_1\)裡面任意兩個數都不相等,利用這點,我們就可以把他轉成一個LIS。

因為LCS是按位的、有順序的,所以我們就可以直接保證選中的順序是一樣的就行了。

比如:

3 2 1 4 5
1 2 3 4 5

\(P_1\)的數在\(P_2\)的那個位置寫出來,即:

3 2 1 4 5

那他的LIS長度就是3了。

然後LIS就可以二分優化了,就不羅嗦了。



  1. 即最長公共子序列的英文縮寫。 ↩︎