CF822E Liar 题解

CF822E Liar 题解

考虑 $f_{i, j} $ 表示香肠前 \(i\) 个字符被分割为 \(j\) 段,最多能匹配希望得到的字符串多少位。

转移分两种,第一种 \(f_{i, j} \rightarrow f_{i + 1, j}\),第二种 \(f_{i, j} + lcp\rightarrow f_{i + lcp, j + 1}\),其中 \(lcp = LCP(s_{i + 1}, t_{f_{i, j} + 1})\)

\(LCP\) 可以用后缀数组或哈希表,分别做到 \(O(nx)\)\(O(nx\log n)\)

// Problem: J - Liar
// Author: Moyou
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
const int N = 2e5 + 10;

struct SuffixA {
    int n, idx, sig, sa[N], sa2[N << 1], tmp[N << 1], buc[N], rk[N << 1], x[N], ht[N], lg[N], st[22][N];
    void init(string s) {
        n = s.size(), s = " " + s;
    	sig = 128, idx = 0;
        for(int i = 1; i <= n; i ++) buc[rk[i] = s[i]] ++;
        for(int i = 1; i <= sig; i ++) buc[i] += buc[i - 1];
        for(int i = n; i; i --) sa[buc[rk[i]] --] = i;
        for(int j = 1; idx < n; j <<= 1, sig = idx) {
            idx = 0; for(int i = n - j + 1; i <= n; i ++) sa2[++ idx] = i;
            for(int i = 0; i <= sig; i ++) buc[i] = 0;
            for(int i = 1; i <= n; i ++) {
                if(sa[i] > j) sa2[++ idx] = sa[i] - j;
                buc[rk[i]] ++;
            }
            for(int i = 1; i <= sig; i ++) buc[i] += buc[i - 1];
            for(int i = n; i; i --) sa[buc[rk[sa2[i]]] --] = sa2[i], tmp[i] = rk[i];
            idx = 0;
            for(int i = 1; i <= n; i ++)
                rk[sa[i]] = ((tmp[sa[i]] == tmp[sa[i - 1]] && tmp[sa[i] + j] == tmp[sa[i - 1] + j]) ? idx : ++ idx);
        }
        for(int i = 1, l = 0; i <= n; i ++) {
            if(l) l --;
            while(s[i + l] == s[sa[rk[i] - 1] + l]) l ++;
            ht[rk[i]] = l;
        }
    }
    void ST() {
        for(int i = 2; i <= n; i ++) lg[i] = lg[i >> 1] + 1;
        for(int i = 1; i <= n; i ++) st[0][i] = ht[i];
        for(int i = 1; i <= lg[n]; i ++)
            for(int j = 1; j + (1 << i) - 1 <= n; j ++)
                st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << i - 1)]);
    }
    int LCP(int i, int j) {
        if(i > j) swap(i, j); i ++;
        if(i <= 1 || j > n) return 0;
        int k = lg[j - i + 1];
        return min(st[k][i], st[k][j - (1 << k) + 1]);
    }
} sa;
int n, m, k, f[N][35];
string s, t;

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> s >> m >> t >> k;
    string S = s + '#' + t;
    sa.init(S), sa.ST();
    memset(f, -0x3f, sizeof f);
    f[0][0] = 0;
    for(int i = 0; i < n; i ++) {
        for(int j = 0; j <= k; j ++) {
            if(f[i][j] >= 0) {
                f[i + 1][j] = max(f[i + 1][j], f[i][j]);
                int lcp = sa.LCP(sa.rk[i + 1], sa.rk[n + 2 + f[i][j]]);
                if(j < k) f[i + lcp][j + 1] = max(f[i + lcp][j + 1], f[i][j] + lcp);
            }
        }
    }
    for(int j = 0; j <= k; j ++) {
        if(f[n][j] == m) {
            cout << "YES\n";
            return 0;
        }
    }
    cout << "NO\n";
    return 0;
}

posted @ 2025-08-19 12:30  MoyouSayuki  阅读(6)  评论(0)    收藏  举报
:name :name