比赛时队友有想法了我就一直在出数据了。
然而那个想法是错的。到快结束的时候才验证了是错的。
都怪自己太懒,没有验证正确性就盲目地同意队友写,然后两个人越改越乱,要多思考啊。
然后比赛快结束的时候我想到了新的解法。就是从后往前匹配。然而就是再给半个小时也做不出来,因为少考虑了一些情况。
题意:给出两个串s,t……现在需要在s的任意字符x后面添加一个字符y(y≠x),问s有没有办法变成t。
思路:
1、把s串作为基准,把t从后往前匹配。
2、上一步有一个遗漏,那就是没有判断第一个字符,最前面的加字符操作一定是在第一个字符之后,所以s和t的第一个字符必须相同。
3、解释一下第一步中为什么如果出现多个x,和最后一个x匹配是最优的呢,假如s是abx,t是abbx,那么新加入的这个b肯定是要放在a之后加进去的,如果新加入的这个b放在原来b之后,那么就会匹配失败啦~然后现在第二步之后(噢现在是10:43)也就是s中的第一个字符和t中的第一个字符匹配,其余的不变 。
4、但是如果s 是 aaa,t是aaabaaa,那就不对了。(啊我真的好跳啊是不是有多动症)也就是说第一个字符必须s和t相同的,特例必须推广到s和t相同并且该字符在s中和第一个字符相同的所有情况。然后就可以过了。(替啦这题解写得我自己都看不下去了语文水平太弱了TAT)
注意事项:
1、据说memset比for快。也就是用时:for整个数组 > memset整个数组 > for n+3 > memset n+3, 但是用最快的memset n+3 如果你傻逼了就会莫名wa。这次就是先memset整个数组了,然后是T了,改成memset n+5 才变成wa
2、数据怎么想出来的呢?首先原来的做法问题出在第一个字符上,那么第一个字符问题解决了之后会不会对第一个字符紧接着的第二个字符有影响呢?如果第二个字符和第一个相同或者不同,会有哪些影响呢?改策略的时候,要考虑与之相关的所有情况。
以下是代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define SIZE_N 100005
using namespace std;
char s[SIZE_N],t[SIZE_N];
int markt[SIZE_N];//,markss[SIZE_N];
int main()
{
int T;
scanf("%d",&T);
while (T--){
scanf("%s",s);
scanf("%s",t);
int suc = 1;
int lenss,lentt;
for (lenss = 0; s[lenss]; lenss++);
for (lentt = 0; t[lentt]; lentt++);
//memset(markss,0,sizeof(int) * (lenss+ 5));
memset(markt,0,sizeof(int) * (lentt+5));//第一次交t了,改一下memset。826的934再交一发
//果然只用372ms了……这道题时间卡的好紧啊……memset都能T了一次
int j = lentt - 1;
if (t[0]!= s[0]|| lenss > lentt){
suc = 0;
}else{
int nows = 0;
for (int i = 0; i < lentt; i++)//改一下第一个元素的处理。再交第n+1次。10:55
if (t[i] == t[0]){
if (t[i] == s[nows]){
markt[i] = 1;
nows++;
}else{
suc = 0;
break;
}
}else{
break;
}
for (int i = lenss - 1; i >= 0; i--){
while ( j >= 0 && t[j] != s[i]){
j--;
}
if (j < 0){
suc = 0;
break;
}
if (i >= nows)
markt[j] = 1;
j--;//避免同样的元素被重复标记
}
}
if (suc != 1){
puts("No");
}else{
puts("Yes");
}
}
return 0;
}
//我知道这种做法错在哪了!aaa和aaabaaa。就会匹配后两个a和第一个a
//还有一组样例就是aaa和aaaabaaa。