当前位置: 首页 > 工具软件 > Rescue! Max > 使用案例 >

Rescue Niwen!(字符串/dp)

锺离德运
2023-12-01

题目
题意:给定一个字符串 s 1 s 2 s 3 . . . s n s_1s_2s_3...s_n s1s2s3...sn,定义它的子串序列为{ s 1 , s 1 s 2 , . . . , s 1 s 2 s 3 . . . s n , s 2 , s 2 s 3 , . . . , s 2 s 3 . . . s n , s 3 , s 3 s 4 , . . . , s n − 1 s n , s n s_1,s_1s_2,...,s_1s_2s_3...s_n,s_2,s_2s_3,...,s_2s_3...s_n,s_3,s_3s_4,...,s_{n-1}s_{n},s_n s1,s1s2,...,s1s2s3...sn,s2,s2s3,...,s2s3...sn,s3,s3s4,...,sn1snsn}。比如字符串 a b c d abcd abcd,它的子串序列为{ a , a b , a b c , a b c d , b , b c , b c d , c , c d , d a,ab,abc,abcd,b,bc,bcd,c,cd,d a,ab,abc,abcd,b,bc,bcd,c,cd,d},求子串序列的最长递增子序列(可以不连续)。
参考
PS:这道题标了2500,但感觉没到这个难度的样子。

思路:
1、前缀字符串一定小于原字符串。
2、预处理,计算原字符串以任意两个位置 i , j i,j i,j为起点的字符串的最长公共前缀。
3、对于以 i i i为起点的字符串,遍历所有起点下标 j j j小于 i i i的字符串,如果以 i i i为起点的字符串 存在比 以 j j j为起点的字符串 的串(有点绕),那么则更新小于 以 i i i为起点的字符串的 子串数量。详见代码。

官方代码(写的挺好的,自己太懒 就不写了_(:з」∠)_)

#include <iostream>

using namespace std;

int16_t lcp[10000 + 5][10000 + 5];

int dp[10000 + 5];

bool is_greater(const string& s, int x, int y) {
    if (lcp[x][y] == static_cast<int>(s.size()) - x) {
        return false;
    }
    return s[x + lcp[x][y]] > s[y + lcp[x][y]];
}

int get_score(const string& s, int x, int y) {
    if (is_greater(s, x, y)) {
        return dp[y] + static_cast<int>(s.size()) - x - lcp[x][y];
    }
    return 0;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        string s;
        cin >> s;
        if (s.size() != n) return 42;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                lcp[i][j] = 0;
            }
        }
        for (int i = n - 1; i >= 0; i--) {
            for (int j = n - 1; j >= 0; j--) {
                if (i == j) {
                    lcp[i][j] = n - i;
                } else
                if (s[i] != s[j]) {
                    lcp[i][j] = 0;
                } else {
                    lcp[i][j] = lcp[i + 1][j + 1] + 1;
                }
            }
        }
        int ans = n;
        dp[0] = n;
        for (int i = 1; i < n; i++) {
            dp[i] = n - i;
            for (int j = 0; j < i; j++) {
                dp[i] = max (dp[i], get_score(s, i, j));
            }
            ans = max(ans, dp[i]);
        }
        cout << ans << '\n';
    }
}
 类似资料: