• CodeForces


    ( ext{Description})

    传送门

    ( ext{Solution})

    我们设 (dp[i][j]) 为将串 (s)(i) 个字符分成 (j) 组后能到达串 (t) 的最大位置。

    转移方程就是:

    [dp[i][j]=max{dp[i][j],dp[i-1][j]} ]

    [dp[i+LCP-1][j+1]=max{dp[i+LCP-1][j+1],dp[i-1][j]+LCP} ]

    其中 (LCP) 就是以 (i) 开始的后缀(这在 (s) 串中)与以 (dp[i-1][j]+1) 开始的后缀(注意这是在 (t) 串中)的 (lcp)

    我们用后缀数组加 ( ext{st}) 表维护 (lcp) 即可。

    ( ext{Code})

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    const int N = 2e5 + 5;
    
    int dp[N][35], x, l1, l2, lg[N], rmq[N][20], n, m, h[N], tax[N], SA[N], tp[N], rk[N], a[N];
    
    int read() {
    	int x = 0, f = 1; char S;
    	while((S = getchar()) > '9' || S < '0') {
    		if(S == '-') f = -1;
    		if(S == EOF) exit(0);
    	}
    	while(S <= '9' && S >= '0') {
    		x = (x << 1) + (x << 3) + (S ^ 48);
    		S = getchar();
    	}
    	return x * f;
    }
    
    bool cmp(const int x, const int y, const int d) {return tp[x] == tp[y] && tp[x + d] == tp[y + d];}
    
    void Sort() {
        for(int i = 0; i <= m; ++ i) tax[i] = 0;
        for(int i = 1; i <= n; ++ i) ++ tax[rk[tp[i]]];
        for(int i = 1; i <= m; ++ i) tax[i] += tax[i - 1];
        for(int i = n; i >= 1; -- i) SA[tax[rk[tp[i]]] --] = tp[i];
    }
    
    void init() {
        char ch[N];
        l1 = read(); scanf("%s", ch);
        for(int i = 1; i <= l1; ++ i) a[i] = ch[i - 1];
        n = l1; a[++ n] = '$';
        l2 = read(); scanf("%s", ch);
        for(int i = n + 1; i <= n + l2; ++ i) a[i] = ch[i - n - 1];
        n += l2;
        m = 122;
        x = read();
    }
    
    void Suffix() {
        init();
        for(int i = 1; i <= n; ++ i) rk[i] = a[i], tp[i] = i;
        Sort();
        for(int w = 1, p = 1, i; p < n; m = p, w <<= 1) {
            for(p = 0, i = n - w + 1; i <= n; ++ i) tp[++ p] = i;
            for(i = 1; i <= n; ++ i) if(SA[i] > w) tp[++ p] = SA[i] - w;
            Sort(); swap(rk, tp); rk[SA[1]] = p = 1;
            for(i = 2; i <= n; ++ i) rk[SA[i]] = cmp(SA[i], SA[i - 1], w) ? p : ++ p;
        }
        int j, k = 0;
        for(int i = 1; i <= n; h[rk[i ++]] = k)
            for(k = k ? k - 1 : k, j = SA[rk[i] - 1]; a[i + k] == a[j + k]; ++ k);
        for(int i = 2; i <= n; ++ i) lg[i] = lg[i >> 1] + 1;
        for(int i = 1; i <= n; ++ i) rmq[i][0] = h[i];
        for(int j = 1; (1 << j) <= n; ++ j)
            for(int i = 1; i + (1 << j) - 1 <= n; ++ i)
                rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << j - 1)][j - 1]);
    }
    
    int lcp(const int x, const int y) {
        int l = rk[x], r = rk[y];
        if(l == r) return n - SA[l] + 1;
        if(l > r) swap(l, r);
        int t = lg[r - l];
        return min(rmq[l + 1][t], rmq[r - (1 << t) + 1][t]);
    }
    
    int main() {
        Suffix();
        for(int i = 1; i <= l1; ++ i)
            for(int j = 0; j < x; ++ j) {
                if(dp[i][j] == l2) {puts("YES"); return 0;}
                dp[i][j] = max(dp[i][j], dp[i - 1][j]);
                int LCP = lcp(i, dp[i - 1][j] + 2 + l1);
                if(LCP > 0) dp[i + LCP - 1][j + 1] = max(dp[i + LCP - 1][j + 1], dp[i - 1][j] + LCP);
                if(dp[i][j] == l2) {puts("YES"); return 0;}
            }
        for(int i = 1; i <= l1; ++ i) if(dp[i][x] == l2) {puts("YES"); return 0;}
        puts("NO");
        return 0;
    }
    
  • 相关阅读:
    Android数字选择器-NumberPicker
    Eclipse上传代码到GitHub
    TortoiseGit上传代码到GitHub
    Git的简单介绍
    Android中的树状(tree)列表
    Android数据适配-ExpandableListView
    Android动画-补间(Tween)动画
    Android动画-帧动画
    Android中样式及主题
    Android消息通知-Notification
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12407526.html
Copyright © 2020-2023  润新知