zoukankan      html  css  js  c++  java
  • Codeforces 1303E Erase Subsequences

    Description

    描述

    给定两个字符串 $s$ 和 $t$。问能否找到 $s$ 的两个不相交的子序列(可以为空) $s_1,s_2$ 使 $t=s_1s_2$。

    输入

    第一行为一个正整数 $T$($1 le T le 100$)表示数据组数。

    接下来每组数据为两个字符串 $s$ 和 $t$($1le|t|le|s|le 400$)。

    输出

    对于每组数据,一个 YESNO 表示是否可行。

    样例

    输入

    4
    ababcd
    abcba
    a
    b
    defi
    fed
    xyz
    x

    输出

    YES
    NO
    NO
    YES

    Solution

    本题解字符串下标从 $1$ 开始。

    看到 $1 le |t| le |s| le 400$,盲猜可能是的三次方的做法。

    根据题意,第一次操作一定是创造了 $t$ 的前半部分,第二次操作一定是创造了 $t$ 的后半部分。于是我们枚举一下这个断点。用 $t_1$ 来表示 $t_{1cdots len_l}$(前一半),$t_2$ 表示 $t_{|t| - len_r+1 cdots |t|}$(后一半),其中 $len_l = |t| - len_r$,也就是 $len_l + len_r = |t|$。

    用 $a_{i, j}$ 表示 $s_{i cdots |s|}$ 中,第一个 $j$ 的位置。也就是 $forall i le k < a_{i,j}, s_k eq j$,同时 $s_{a_{i,j}} = j$。如果 $forall i le k le |s|, s_i e j$ ,那么有 $a_{i,j} = infty$。

    考虑 DP,用 $f_{i, j}$ 表示至少需要 $s_1 sim s_{f_{i,j}}$,才能匹配 $t_{1 1 cdots i}$ 和 $t_{2 1 cdots j}$。转移当然是考虑这次匹配 $t_{1 i}$ 还是匹配 $t_{2 j}$,如果是前者,$f_{i,j} = a_{f_{i - 1, j} + 1, t_{1 i}}$(也就是 $f_{i - 1, j}$ 后面第一个 $t_{1 i}$ 的位置);如果是后者,就有 $f_{i,j} = a_{f_{i, j - 1} + 1, t_{2 j}}$。两者取个 $min$ 即可。最终的成功与否取决于 $f_{len_l, len_r}$ 是否等于 $infty$。如果 $a$ 已经求出来了,这部分将是 $O(|t|^2)$ 的。但是外层还要枚举断点,所以其实是 $O(|t|^3)$。

    至于 $a$ 的话,可以从 $|s| o 1$ 更新,首先把 $a_{i}$ 复制为 $a_{i + 1}$,然后把 $a_{i, s_i}$ 更新为 $i$ 即可。这个是 $O(Sigma cdot |s|)$ ($Sigma$ 表示字符集大小)的,常数比较优秀。当然也可以按照定义写一个 $O(Sigma cdot |s|^2)$ 的,不影响时间复杂度。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 405;
    int f[N][N], a[N][30];
    const int INF = 0x3f3f3f3f;
    int main()
    {
    	ios::sync_with_stdio(false);
    	int t;
    	cin >> t;
    	while(t--)
    	{
    		string s, t;
    		cin >> s >> t;
    		int ls = s.size(), lt = t.size();
    		s = " " + s;
    		t = " " + t;
    		bool ok = false;
    		for(int lenl = 1; lenl <= lt; lenl++)
    		{
    			string t1 = " " + t.substr(1, lenl);
    			string t2 = " " + t.substr(lenl + 1, lt - lenl);
    			memset(f, 0, sizeof f);
    			f[0][0] = true;
    			memset(a[ls + 1], 0x3f, sizeof a[ls + 1]);
    			for(int i = ls; i; i--)
    			{
    				memcpy(a[i], a[i + 1], sizeof a[i]);
    				a[i][s[i] - 'a'] = i;
    			}
    			int lenr = lt - lenl;
    			memset(f, 0x3f, sizeof f);
    			f[0][0] = 0;
    			for(int i = 0; i <= lenl; i++)
    			{
    				for(int j = 0; j <= lenr; j++)
    				{
    					if(i && f[i - 1][j] != INF)
    						f[i][j] = min(f[i][j], a[f[i - 1][j] + 1][t1[i] - 'a']);
    					if(j && f[i][j - 1] != INF)
    						f[i][j] = min(f[i][j], a[f[i][j - 1] + 1][t2[j] - 'a']);
    				}
    			}
    			if(f[lenl][lenr] != INF)
    			{
    				ok = true;
    				break;
    			}
    		}
    		cout << (ok ? "YES" : "NO") << endl;
    	}
    	return 0;
    }
  • 相关阅读:
    HDU1058Humble Numbers(DP)
    HDU1285确定比赛名次(拓扑排序)
    HDU2602Bone Collector(DP,0/1背包)
    HDU1869六度分离(最短路floyd)
    HDU3342Legal or Not(拓扑)
    Dijkstra不能得到含有负权边图的单源最短路径
    HDU1069Monkey and Banana(DP)
    HDU1176免费馅饼(DP)
    DAG上的动态规划
    网络分析中数据包结构的定义
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/CF1303E.html
Copyright © 2011-2022 走看看