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.卡在用主串去匹配翻译后的串那里,此思路过不了第一个样例.

posted @ 2020-12-31 22:39  acmloser  阅读(131)  评论(0编辑  收藏  举报