Codeforces Round #138 (Div. 1) B. Two Strings(子序列染色,附判断子序列套路)

本文深入探讨了如何使用T串去匹配S串的任意子序列,并通过染色标记已匹配部分,最终判断S串是否完全被覆盖。文章详细介绍了算法的实现思路,包括正向和逆向匹配过程,以及如何通过比较最远匹配距离来确定匹配的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

 

 

题意:

       用T串去匹配S串的任意子序列,如果匹配成功,将S种相应位置染色,可重复染色,若最后S

串中所有位置均被染色,输出“Yes”,否则,输出“No”。

思路:

      按照判断子序列的思路匹配,如果Si和Tj匹配(Tj前面的均已被匹配),记录下j的位置,代表Si所能

匹配到的最远距离,若不匹配,找Si前面最近的和Si字符相同的位置,用其匹配的最远距离给Si赋值,这

样一趟下来我们可以求出S每个字符在T中匹配到的最远距离,即S中小于等于i的字符均已经被匹配,且最

后一个字符匹配到T的某个位置,到这里,如果我们能倒序求出S中每个字符匹配的最远距离(针对原串末

尾而言),然后将这两个最远距离做小比较即可判断该字符是否存在在一个和T匹配的子序列中。

代码实现:

#include<iostream>
#include<cstring>
#include<cmath>
#include<stack>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+100;
/*  // 判断t是否为s的子序列 
bool isSubsequence(string s, string t) {
    int pos_t = 0;
    for(int i = 0 ; i < s.size() && pos_t < t.size(); i ++) {
        if(t[pos_t] == s[i]){
        	pos_t++;
		}
    }
    return pos_t==t.size();
}*/
char s[N],t[N];
int Left[N],Right[N],pre[N],len1,len2;
void judge(char *s,char *t,int *arr){
	memset(pre,0,sizeof(pre));
	for(int i=1,p=1;i<=len1;i++){
		arr[i]=pre[s[i]];
		if(s[i]==t[p]&&p<=len2){
			arr[i]=p++;
		}
		pre[s[i]]=arr[i];
	}
}
int main() {

	bool flag=0;
	while(scanf("%s",s+1)!=EOF){
		scanf("%s",t+1);
		flag=1;
		memset(Left,0,sizeof(Left));
		memset(Right,0,sizeof(Right));

		len1=strlen(s+1);
		len2=strlen(t+1);
		
		judge(s,t,Left);
		reverse(s+1,s+1+len1);
		reverse(t+1,t+1+len2);

		judge(s,t,Right);
		reverse(s+1,s+1+len1);
		reverse(t+1,t+1+len2);
		
		for(int i=1;i<=len1;i++){
			if(Left[i]==0||Right[i]==0||Left[i]<len2+1-Right[len1+1-i]){
				flag=0;//Right的转换别弄错 
				break;
			}
		}
		
		if(flag)cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
		
	}
	return 0;

}

THE END;

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值