CF 1303E Erase Subsequences

Erase Subsequences

题意:

给一个 \(S\) 串和一个 \(T\) 串,问是否能由 \(S\) 在两次以内生成 \(T\)

\(S1\) 一次生成 \(S2\) 是指:从 \(S1\) 取出一个子序列 \(S2\) 并删除,不改变原顺序。

\(S1\) 两次生成 \(S2\) 是指:在 \(S1\) 一次生成 \(T1\) 之后,用剩下的 \(S1\) 生成 \(T2\)\(S2=T1+T1\)

其中 \(len(S), len(T) \le 400\)

题解:

由数据范围可知复杂度为 \(O(N^3)\),而此题与上一场 div3 的 E1 (CF1296E1) 题其实有近似之处,相当于用两次自定义的权值顺序去构造出新串。其实就是最长公共子序列的做法改编。可知 LCS 的复杂度为 \(O(N^2)\),外层套一维枚举 \(T1\)\(T2\) 的分割点复杂度为 \(O(N)\)

剩下的部分就很显然了,构造 \(dp_{i,j}\) 表示 \(S\) 枚举到 \(i\)\(T1\) 枚举到 \(j\)\(T2\) 能取的最大值。

  • 第一种转移是不需要条件的 \(dp_{i,j} = dp_{i-1,j}\) 表示多了一层 \(S\) 但是没有作出任何贡献

  • 第二种转移是第二维增加 \(dp_{i,j} = dp_{i-1,j-1}\) 表示 \(S_i\)\(T1_j\) 匹配上了

  • 第三种转移是第一维增加 \(dp_{i,j} = dp_{i-1,j + 1}\) 表示 \(S_i\)\(T2_{dp[i - 1][j]}\) 匹配上了

代码:

#include <bits/stdc++.h>
#define ll long long
#define X first
#define Y second
#define sz size()
#define all(x) x.begin(), x.end()
using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<long long> vl;

template <class T>
inline bool scan(T &ret){
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return 0; //EOF
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}

const ll mod = 1e9+7;
const int maxn = 405+50;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;

ll qp(ll x, ll n) {
    ll res = 1; x %= mod;
    while (n > 0) {
        if (n & 1) res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}

// dp[i][j] s(1~i), t1(1~j), t2 val

char s[maxn], t[maxn];
int slen, tlen;

int main(int argc, char* argv[]) {
    int T;
    scanf("%d", &T);
    for (int kase = 1; kase <= T; ++kase) {
        scanf("%s%s", s + 1, t + 1);
        slen = strlen(s + 1);
        tlen = strlen(t + 1);
        int flag = 0;
        for (int pos = 1; pos <= tlen; ++pos) {
            vector<vector<int> > dp(slen + 1);
            for (int i = 0; i <= slen; ++i) {
                dp[i].resize(pos + 1);
                for (int j = 0; j <= pos; ++j) {
                    dp[i][j] = -1;
                }
            }
            dp[0][0] = 0;
            for (int i = 1; i <= slen; ++i) {
                for (int j = 0; j <= min(i, pos); ++j) {
                    dp[i][j] = dp[i - 1][j];
                    if (dp[i - 1][j] != -1 && dp[i - 1][j] < tlen - pos && s[i] == t[dp[i - 1][j] + pos + 1]) {
                        dp[i][j] = max(dp[i][j], dp[i - 1][j] + 1);
                    }
                    if (j && s[i] == t[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1]);
                }
            }
//            if (pos == 2) {
//                for (int i = 0; i <= slen; ++i) {
//                    for (int j = 0; j <= pos; ++j) {
//                        printf("%d ", dp[i][j]);
//                    }
//                    printf("\n");
//                }
//            }
            if (dp[slen][pos] == tlen - pos) {
                flag = 1;
                break;
//                    cerr << pos << endl;
            } else if (dp[slen][pos] == -1) break;
        }
        printf("%s\n", flag ? "YES" : "NO");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/badcw/p/12313134.html