题目
【描述】
给定两个字符串 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 ∣ < = 7 |s|,|t|<=7 ∣s∣,∣t∣<=7。
对于60%的数据, ∣ s ∣ , ∣ t ∣ < = 300 |s|,|t|<=300 ∣s∣,∣t∣<=300。
对于100%的数据, T < = 100 T<=100 T<=100, ∣ s ∣ , ∣ t ∣ < = 30000 |s|,|t|<=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]=='*'\ and\ f[i][j-1]\ and\ s[i-1]==t[j])\ or\ (s[i]=='*'\ and\ f[i-1][j])
f[i][j]=(s[i]==t[j] and f[i−1][j−1]) or (s[i]==′∗′ and f[i][j−1] and s[i−1]==t[j]) or (s[i]==′∗′ and f[i−1][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;
}