洛谷 P7469 [NOI Online 2021 提高组] 积木小赛(民间数据) 题解

一、题目:

洛谷原题

二、思路:

简化题意,求出在\(t\)串中有多少个本质不同的子串与\(s\)串中的某个子序列相同。

看到子串,当然先想后缀自动机。

考虑在SAM上动态规划。

\(dp(i, x)\)表示考虑了\(s\)串的前\(i\)个字符,在后缀自动机的\(substrings(x)\)中所能与\(s\)串子序列匹配的最大长度。

例如\(substrings(x)=\{"abcbc","bcbc","cbc","bc"\}\)\(s[1\sim 8]="ebcbcbda"\)。则\(dp(8, x) = 4\)

对于任意一个状态\(st\),很容易发现一个性质:若\(substrings(st)\)中有长度为\(len\)的一个后缀可以被匹配,则长度为\(len-1,len-2,...,minlen(st)\)这些后缀都可以被匹配。

所以最后的答案\(ans = \sum_{st}(dp(n,st)-minlen(st) + 1)\)

哦,忘了讲怎么转移了。

\(dp(i,x)=\max_{node[y].ch[s_i]=x}\{dp(i-1,y)\}+1\)

当然第一维可以滚动掉。

三、代码:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 3005;

int n, las = 1, tot = 1;

int dp[maxn << 1], tmp[maxn << 1];
char s[maxn], t[maxn];

struct Node {
    int len, fa;
    int ch[27];
}node[maxn << 1];

inline void extend(int c) {
    int v = las, z = ++ tot; las = tot;
    node[z].len = node[v].len + 1;
    for (; v && node[v].ch[c] == 0; v = node[v].fa) node[v].ch[c] = z;
    if (!v) node[z].fa = 1;
    else {
        int x = node[v].ch[c];
        if (node[x].len == node[v].len + 1) node[z].fa = x;
        else {
            int y = ++ tot;
            node[y] = node[x];
            node[y].len = node[v].len + 1;
            node[x].fa = node[z].fa = y;
            for (; v && node[v].ch[c] == x; v = node[v].fa) node[v].ch[c] = y;
        }
    }
}

inline void chkmax(int &x, int y) {
    x = y > x ? y : x;
}

int main() {
    scanf("%d", &n);
    scanf("%s", s + 1);
    scanf("%s", t + 1);
    for (int i = 1; i <= n; ++ i) extend(t[i] - 'a' + 1);

    for (int i = 1; i <= n; ++ i) {
        int c = s[i] - 'a' + 1;
        for (int j = 1; j <= tot; ++ j) tmp[j] = dp[j];
        for (int j = 1; j <= tot; ++ j) {
            if (node[j].ch[c] != 0) {
                chkmax(dp[node[j].ch[c]], tmp[j] + 1);
            }
        }
    }
    int ans = 0;
    for (int i = 2; i <= tot; ++ i) {
        ans += max(0, dp[i] - node[node[i].fa].len);
    }
    printf("%d\n", ans);
    return 0;
}

posted @ 2021-03-28 17:27  蓝田日暖玉生烟  阅读(113)  评论(0编辑  收藏  举报