Codeforces 1303E.Erase Subsequences(dp压维)

题目链接:

  https://codeforces.ml/problemset/problem/1303/E

解题思路:

  参考大佬的视频:https://www.bilibili.com/video/BV1H74113746 from=search&seid=5562208735290586020
  自我吐槽:这都能dp…
  将 t t t字符串分成前后两个字符串 t 1 t1 t1, t 2 t2 t2字符串,接下来设置dp状态, d p [ l e n s ] [ l e n t 1 ] [ l e n t 2 ] = 1 dp[lens][lent1][lent2]=1 dp[lens][lent1][lent2]=1,就代表s字符串的前 l e n s lens lens的长度存在两个不重叠的子序列
  很显然当 d p [ l e n s ] [ l e n t 1 ] [ l e n t 2 ] = 1 dp[lens][lent1][lent2]=1 dp[lens][lent1][lent2]=1, d p [ l e n s + 1 ] [ l e n 1 ] [ l e n 2 ] = 1 dp[lens+1][len1][len2]=1 dp[lens+1][len1][len2]=1
  如果 s [ l e n s ] = = t 1 [ l e n t 1 ] s[lens]==t1[lent1] s[lens]==t1[lent1]
  那么 d p [ l e n s + 1 ] [ l e n t 1 + 1 ] [ l e n 2 ] = m a x ( d p [ l e n s + 1 ] [ l e n t 1 + 1 ] [ l e n 2 ] , d p [ l e n s ] [ l e n 1 ] [ l e n 2 ] ) dp[lens+1][lent1+1][len2]=max(dp[lens+1][lent1+1][len2],dp[lens][len1][len2]) dp[lens+1][lent1+1][len2]=max(dp[lens+1][lent1+1][len2],dp[lens][len1][len2])
  如果 s [ l e n s ] = = t 2 [ l e n t 2 ] s[lens]==t2[lent2] s[lens]==t2[lent2]
  那么 d p [ l e n s + 1 ] [ l e n t 1 ] [ l e n t 2 + 1 ] = m a x ( d p [ l e n s + 1 ] [ l e n t 1 ] [ l e n t 2 + 1 ] , d p [ l e n s ] [ l e n 1 ] [ l e n 2 ] ) dp[lens+1][lent1][lent2+1]=max(dp[lens+1][lent1][lent2+1],dp[lens][len1][len2]) dp[lens+1][lent1][lent2+1]=max(dp[lens+1][lent1][lent2+1],dp[lens][len1][len2])
  最后: d p [ l e n s + 1 ] [ l e n 1 ] [ l e n 2 ] = m a x ( d p [ l e n s + 1 ] [ l e n 1 ] [ l e n 2 ] , d p [ l e n s ] [ l e n 1 ] [ l e n 2 ] ) dp[lens+1][len1][len2]=max(dp[lens+1][len1][len2],dp[lens][len1][len2]) dp[lens+1][len1][len2]=max(dp[lens+1][len1][len2],dp[lens][len1][len2])
  这个理论上可解,但是时间不允许,加上划分 t 1 , t 2 t1,t2 t1,t2字符串需要 O ( n ) O(n) O(n)时间,总复杂度为 O ( n 4 ) O(n^4) O(n4)
  重点来了!!!
  对于状态只有01的dp往往可以压缩一维!!!
  选择将最后一维压缩到状态中,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]就代表 s s s中匹配到 i i i, t 1 t1 t1中匹配到 j j j t 2 t2 t2中最大的匹配位置

AC代码:

#include<bits/stdc++.h>
using namespace std;
int T;
int dp[410][410];
bool check(string s,string t) {
	int ls=s.size(),lt=t.size(),idx=0;
	for(int i=0; i<ls; i++)
		if(s[i]==t[idx]) idx++;
	if(idx==lt) return true;
	else return false;
}
bool check(string s,string t1,string t2) {
	//cout<<t1<<" "<<t2<<endl;
	memset(dp,-1,sizeof(dp));//初始化为-1
	dp[0][0]=0;
	int ls=s.size(),lt1=t1.size(),lt2=t2.size();
	for(int i=0; i<ls; i++) 
	    for(int j=0; j<=lt1; j++)
	        if(dp[i][j]>=0) {//代表该状态能否推导下一状态
	        	if(j<lt1&&t1[j]==s[i])
	        		dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]);
	        		//因为匹配的是t1字符串,所以不用dp值加一
	        	if(dp[i][j]<lt2&&t2[dp[i][j]]==s[i]) 
	        	    dp[i+1][j]=max(dp[i+1][j],dp[i][j]+1);
	        	    //匹配t2字符串,符合条件的话,dp[i][j]值加一
	        	dp[i+1][j]=max(dp[i+1][j],dp[i][j]);
	        	   //当前第i个字符都不匹配
			}
	if(dp[ls][lt1]>=lt2) return true;//如果最后的dp值大于等于lt2即可
	else return false;
}
void solve() {
	string s,t;
	cin>>s>>t;
	if(check(s,t)) {//先判断t是不是s的子序列再划分
		printf("YES\n");
		return;
	}
	int lt=t.size();
	for(int i=0; i<lt-1; i++) {
		string t1="",t2="";
		for(int j=0; j<=i; j++) t1+=t[j];
		for(int j=i+1; j<lt; j++) t2+=t[j];
		if(check(s,t1,t2)) {
			printf("YES\n");
			return;
		}
	}
	printf("NO\n");
	return;
}
int main() {
	cin>>T;
	while(T--) solve();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值