Loading

CF223B Two Strings 题解

题目链接

题目分析

题目很短,只有两句话,可分析的不多,似乎难以入手,我们不妨换一个思路转化一下题意,改为:是否对于 \(s\) 中的每一个字符,总有一个等于 \(t\)\(s\) 的子序列覆盖它。

因此,我们可以考虑对于每一个字符,通过前后拼接的方式覆盖它,但是前后满足条件的子序列有很多,我们必须缩小范围。

考虑一下子序列的性质可以发现,总有一个等于 \(t\) 的子序列(如果 \(s\) 中有等于 \(t\) 的子序列),它的每一个元素在 \(s\) 中的下标都不晚于其他子序列的下标,这个结论很好证明,如果有一个不符合的那他肯定就不是这个最早的子序列。

知道了这个性质,来考虑前后拼接,我们对于 \(s\) 的每一个字符 \(s_i\),求出当 \(s\) 的子序列 \(u\)\(s_i\) 为结尾时,它最长能匹配到的 \(t\) 的位置,前后都求一遍,记为 \(j\)\(k\),因为具有前面提到的子序列的性质,这个位置一定是在 \(t\) 中最后面或者最前面的,所以如果 \(j<k\) 或者两个里有任意一个无法匹配,就无解,否则有解。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector> 
#define ll long long
using namespace std;
int pos[30];
int l[1000001],r[1000001];
int main(){
	string s,t;
	cin>>s>>t;
	int cnt=0,n=s.length(),m=t.length();
	memset(r,0x3f,sizeof(r));
	for(int i=0;i<n;i++){
		if(cnt!=m && s[i]==t[cnt]){
			l[i]=cnt+1;
			pos[s[i]-'a'+1]=cnt+1;
			cnt++;
		}
		else l[i]=pos[s[i]-'a'+1];
	}
	memset(pos,0,sizeof(pos));
	cnt=m-1;
	for(int i=n-1;i>=0;i--){
		if(cnt!=-1 && s[i]==t[cnt]){
			r[i]=cnt+1;
			pos[s[i]-'a'+1]=cnt+1;
			cnt--;
		}
		else r[i]=pos[s[i]-'a'+1];
	}
	for(int i=0;i<n;i++){
		if(l[i]<r[i] || (l[i]==0 || r[i]==0)){
			cout<<"No";
			return 0;
		}
	}
	cout<<"Yes";
	return 0;
}

posted @ 2023-01-16 20:58  eastcloud  阅读(44)  评论(0编辑  收藏  举报