GMOJ6934. 2020.01.01冬令营模拟 改(transform)

GMOJ6934. 改(transform)

\(Description\)

\(T\) 组询问,每次询问有两个字符串 \(A\)\(B\) 。求 \(A\) 的子串中,有多少存在一个子序列,可以由 \(B\) 经过下列变换可以变为: 对于一个字符串,每次取出开头的字符,将其插入到一个初始为空的双端队列的开头或结尾,最后双端 队列从左到右形成的串即为变换后的串。

\(Data \ Constraint\)

\(T \leq 8, \ |A| \leq 4096, \ |B| \leq 2048\)

\(Solution\)

由变换的方式可以得出 \(B\)\(A\) 上的匹配方式:从 \(A_i = B_1\) 开始,向 \(i\) 的左或右扩展。

并且每个匹配可以由 \((l, r, k)\) 表示,其中 \(B_{1..k}\) 可以匹配 \(A_{l..r}\) 的子串,那么我们可以设 \(dp\) 状态 \(f_{l, r}\) 表示 \(A_{l..r}\) 能匹配到的最大的 \(k\)

\[f_{l, r} \Rightarrow \begin{cases} f_{l - 1, r} + [A_l = B_{f_{l - 1, r} \ \ + 1}] \\[2ex] f_{l, r - 1} + [A_r = B_{f_{l, r - 1} \ \ + 1}] \\[2ex] \end{cases} \]

根据 \(f\) 可以求出 \(Next_i\) 表示最小的 \(j\) 使得存在匹配 \((i, j, |B|)\),那么答案即为 \(\sum{|A| - Next_i + 1}\)

时间复杂度 \(O(|A|^2)\),需要适当卡常。

\(Code\)

#include <cstdio>
#include <cstring>

using namespace std;

#define N 4096

#define fo(i, x, y) for(i = x; i <= y; ++ i)
#define fd(i, x, y) for(i = x; i >= y; -- i)

char ch[N + 1];

int Next[N + 1], a[N + 1], b[N + 1];

int f[N + 1][N + 1];

int n, m;

int Max(int x, int y) { return x > y ? x : y; }
int Min(int x, int y) { return x < y ? x : y; }

int main() {
    freopen("transform.in", "r", stdin);
    freopen("transform.out", "w", stdout);

    int T, t, v, k; scanf("%d\n", &T);
    long long ans;
    register int i, j, Case, u;
    fo(Case, 1, T) {
        scanf("%s\n", ch + 1); n = strlen(ch + 1);
        fo(i, 1, n) a[i] = ch[i] - 'a';
        scanf("%s\n", ch + 1); m = strlen(ch + 1);
        fo(i, 1, m) b[i] = ch[i] - 'a';

        fo(i, 1, n) Next[i] = n + 1;
        fo(i, 1, n) fo(j, i, n) f[i][j] = 0;
        fo(i, 1, n) if (a[i] == b[1])
            f[i][i] = 1;
        fo(i, 1, n) fd(u, n - i + 1, 0) if (Next[u] > n) {
            v = u + i - 1;
            if (f[u][v] == m) {
                Next[u] = v; continue;
            }
            if (u > 1)
                f[u - 1][v] = Max(f[u - 1][v], f[u][v] + (a[u - 1] == b[f[u][v] + 1]));
            if (v < n)
                f[u][v + 1] = Max(f[u][v + 1], f[u][v] + (a[v + 1] == b[f[u][v] + 1]));
        }
        fd(i, n - 1, 1) Next[i] = Min(Next[i], Next[i + 1]);
        ans = 0;
        fo(i, 1, n) if (Next[i] <= n)
            ans += n - Next[i] + 1;
        printf("%lld\n", ans);
    }

    return 0;
}
posted @ 2021-01-10 21:28  buzzhou  阅读(61)  评论(0编辑  收藏  举报