CodeForces - 822E Liar

我们设\(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\)与\(dp[i-1][j]+1\)的\(lcp\)。

我们用后缀数组维护\(lcp\)即可。

#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;
}

原文地址:https://www.cnblogs.com/AWhiteWall/p/12407526.html

时间: 2024-08-30 18:11:46

CodeForces - 822E Liar的相关文章

Liar CodeForces - 822E (dp,后缀数组)

大意: 给定串$s,t$, 给定整数$x$, 求判断$t$是否能划分为至多$x$段, 使这些段在$s$中按顺序,不交叉的出现. 设$dp_{i,j}$表示$s$匹配到$i$位, 划分了$j$段, 匹配到$t$中的最大位置 每次取一个极长的lcp转移即可, lcp可以二分哈希或者用后缀数组+RMQ求 #include <iostream> #include <sstream> #include <algorithm> #include <cstdio> #in

Codeforces Round #422 (Div. 2) E. Liar 后缀数组+RMQ+DP

E. Liar The first semester ended. You know, after the end of the first semester the holidays begin. On holidays Noora decided to return to Vi?kopolis. As a modest souvenir for Leha, she brought a sausage of length m from Pavlopolis. Everyone knows th

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

Codeforces 124A - The number of positions

题目链接:http://codeforces.com/problemset/problem/124/A Petr stands in line of n people, but he doesn't know exactly which position he occupies. He can say that there are no less than a people standing in front of him and no more than b people standing b

Codeforces 841D Leha and another game about graph - 差分

Leha plays a computer game, where is on each level is given a connected graph with n vertices and m edges. Graph can contain multiple edges, but can not contain self loops. Each vertex has an integer di, which can be equal to 0, 1 or  - 1. To pass th

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

链接: http://codeforces.com/problemset/problem/506/A 题意: 给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石. 题解: 容易想到DP,dp[i][j]表示到达 i 处,现在步长为 j 时最多收集到的财富,转移也不难,cnt[i]表示 i 处的财富. dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1]) dp[i+st

Codeforces 772A Voltage Keepsake - 二分答案

You have n devices that you want to use simultaneously. The i-th device uses ai units of power per second. This usage is continuous. That is, in λ seconds, the device will use λ·ai units of power. The i-th device currently has bi units of power store

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Codeforces Round #408 (Div. 2) B

Description Zane the wizard is going to perform a magic show shuffling the cups. There are n cups, numbered from 1 to n, placed along the x-axis on a table that has m holes on it. More precisely, cup i is on the table at the position x?=?i. The probl