Clairewd’s message HDU - 4300
KMP+前后缀匹配
别人眼里的模板题我能做N个小时...
错解思路:
将所给的未转化完成的字符串全部转化为第二种状态(即未翻译的状态),和上题一样的思路,将原串和新串和空格拼接在一起求公共前后缀,再利用公共前后缀求剩下的还未被纳入第二部分的原串.如果这样写易错点是aaaaa(密码文里a->a),这种就拼接的新串是aaaaa aaaaa,这样求不出公共前后缀,如果将此情况看成特例的话,我在最后处理时是一个字符一个字符的输出,这样又TLE
修正思路:
kmp前后缀匹配不一定要在一个串上,利用next数组匹配,根据这道题,我们可以利用一半的性质将前后缀分开,将后缀看成主串,前缀看成模式串,后缀一定比前缀小,当匹配的循环结束时,最后匹配的地方就是第二部分所对应的地方,这时将此地方到第二部分全部转化为第二状态即可
易错点:
存在一个字符也不匹配的情况,这时数组要开大,否则会RE
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <unordered_map> 5 using namespace std; 6 const int M = 30; 7 const int N = 100010; 8 unordered_map<char,char> um,jm;//第二部分->第一部分 第一部分->第二部分 9 char pwd[M],text[N*2],prime[N];//TLE原因:可能是一个字符一个字符地输出导致TLE 10 int ne[N]; 11 int main() 12 { 13 int t; 14 scanf("%d",&t); 15 while(t--){//解题关键:(len+1)/2之前的部分一定为密码串,我们可以看后半部分匹配到第一部分什么位置 16 fill(text,text+N,0); 17 scanf("%s",pwd); scanf("%s",text+1); 18 int len = strlen(text+1), k = 0,x = 0; 19 for(int i=0;i<26;i++) { um['a'+i] = pwd[i]; jm[pwd[i]] = 'a'+i; } 20 for(int i=(len+1)/2+1;i<=len;i++) prime[++k] = um[text[i]]; //后半部分 转化为第一部分匹配 21 for(int i=2,j=0;i<=len;i++){//求next数组 22 while(j&&text[i]!=text[j+1]) j = ne[j]; 23 if(text[i]==text[j+1]) j++; 24 ne[i] = j; 25 } 26 for(int i=1;i<=k;i++){//模式串一定比主串长 27 while(x&&text[x+1]!=prime[i]) x = ne[x]; 28 if(text[x+1]==prime[i]) x++; 29 } 30 for(int i=x+1;i<=len-x;i++) text[len+i-x] = jm[text[i]]; 31 printf("%s\n",text+1); 32 } 33 return 0; 34 }
2021.3.7 二刷 完全没想到解题的关键点len+1>>1.卡在用主串去匹配翻译后的串那里,此思路过不了第一个样例.