某NOIP模拟赛 T1 字符串(string)

题目

【描述】

给定两个字符串 s,t,其中s只包含小写字母以及*,t只包含小写字母。

你可以进行任意多次操作,每次选择 s中的一个*,将它修改为任意多个(可以是 0个)它的前一个字符。问是否能将 s修改为t。

有多组数据。

【输入】

第一行一个整数T表示数据组数。

每组数据两行,第一行一个字符串 s,第二行一个字符串 t。

【输出】

每组数据输出一行,如果能将 s修改为t,输出Yes,否则输出No。

【输入样例】

2 
a* 
aaaa 
a* 
ab 

【输出样例】

Yes 
No 

【子任务】

对于20%的数据, ∣ s ∣ , ∣ t ∣ &lt; = 7 |s|,|t|&lt;=7 s,t<=7

对于60%的数据, ∣ s ∣ , ∣ t ∣ &lt; = 300 |s|,|t|&lt;=300 s,t<=300

对于100%的数据, T &lt; = 100 T&lt;=100 T<=100 ∣ s ∣ , ∣ t ∣ &lt; = 30000 |s|,|t|&lt;=30000 s,t<=30000

简要题意:原题够简要了


20%解

首先我们发现多个*连在一起与一个*是等价的。我们只要枚举每个*把上一个字母复
制了多少遍就行了。
—— 鲁迅伪·官方 题解

反正我不会写

而且反正输出No也能得20分

60%解

f [ i ] [ j ] f[i][j] f[i][j]表示 s [ 1... i ] s[1...i] s[1...i]能否与 t [ 1.. j ] t[1..j] t[1..j]匹配,转移方程
f [ i ] [ j ] = ( s [ i ] = = t [ j ]   a n d   f [ i − 1 ] [ j − 1 ] )   o r   ( s [ i ] = = ′ ∗ ′   a n d   f [ i ] [ j − 1 ]   a n d   s [ i − 1 ] = = t [ j ] )   o r   ( s [ i ] = = ′ ∗ ′   a n d   f [ i − 1 ] [ j ] ) f[i][j]=(s[i]==t[j]\ and\ f[i-1][j-1])\ or\ (s[i]==&#x27;*&#x27;\ and\ f[i][j-1]\ and\ s[i-1]==t[j])\ or\ (s[i]==&#x27;*&#x27;\ and\ f[i-1][j]) f[i][j]=(s[i]==t[j] and f[i1][j1]) or (s[i]== and f[i][j1] and s[i1]==t[j]) or (s[i]== and f[i1][j])

当时就想到了,写出来了,然后也苟到了60分。当时是仿照LCS想到的。

时间复杂度: O ( ∣ s ∣   ∣ t ∣ ) O(|s|\ |t|) O(s t)

代码:

#include<bits/stdc++.h>
using namespace std;
int getint(){
	int ans=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		ans=ans*10+c-'0';
		c=getchar();
	}
	return ans*f;
}
#define N 3010
bool f[N][N];
char s_[N],s[N],t[N];
int main(){
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	int n=getint();
	while(n--){
		memset(f,0,sizeof(f));
		memset(s,0,sizeof(s));
		//memset(t,0,sizeof(t));
		//memset(s_,0,sizeof(s_));
		scanf("%s%s",s_,t);
		//cout<<s_<<endl<<t<<endl<<endl;
		f[0][0]=(s_[0]==t[0]);
		if(!f[0][0]){
			puts("No");
			continue;
		}
		int s_len=strlen(s_);
		register int slen=1,tlen=strlen(t);
		s[0]=s_[0];
		for(int i=1;i<s_len;i++)if(s_[i]!='*'||s_[i-1]!='*')s[slen++]=s_[i];
		//cout<<s<<endl;
		for(register int i=1;i<slen;++i){
			for(register int j=0;j<tlen;++j){
				if(s[i]=='*'){
					f[i][j]=(f[i-1][j]||(j>0&&f[i][j-1]&&s[i-1]==t[j]));
				}else if(j!=0){
					f[i][j]=(f[i-1][j-1]&&s[i]==t[j]);
				}
				//cout<<f[i][j];
			}
			//cout<<endl;
		}
		if(f[slen-1][tlen-1])puts("Yes");
		else puts("No");
	}
	return 0;
}

100%解

把两个串都分成尽可能长的很多段,每一段字母相同(可以为*)。然后看每一段,若这一段:

  • s与t的字母不一样

  • s有*但是字母数量比t的多

  • s没有*但是字母数量不同于t

  • s(t)把所有段遍历完了但t(s)还没有(段的数量不同)

那么就不符要求。

代码:

#include<bits/stdc++.h>
using namespace std;
int getint(){
	int ans=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		ans=ans*10+c-'0';
		c=getchar();
	}
	return ans*f;
}

int main(){
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	int t=getint();
	while(t--){
		string s,t;
		cin>>s>>t;
		if(s[0]!=t[0]){
			puts("No");
			continue;
		}
		int snow=0,tnow=0,scnt=0,tcnt=0;bool brk=0;
		while(snow<s.size()&&tnow<t.size()){
			scnt=0,tcnt=0;
			bool star=0;
			char c=s[snow],ct=t[tnow];
			//cout<<"{}"<<c<<" "<<ct<<endl;
			while(snow<s.size()-1&&(s[snow+1]==c||s[snow+1]=='*'))snow++,scnt+=(s[snow]!='*'),star=(s[snow]=='*')|star;
			while(tnow<t.size()-1&&t[tnow+1]==ct)tnow++,tcnt++;
			if(scnt>tcnt||(scnt!=tcnt&&!star)){
				puts("No");brk=1;
				break;
			}
			if((snow==s.size()-1)!=(tnow==t.size()-1)){
				puts("No");brk=1;
				break;
			}
			if(c!=ct){
				puts("No");brk=1;
				break;
			}
			if((snow==s.size()-1)&&(tnow==t.size()-1)){
				puts("Yes");brk=1;
				break;
			}
			snow++;
			tnow++;
		}
		if(!brk)puts("No");
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值