[kmp,不要过多调用strlen!!!] Codeforces 1200E Compress Words
题目:http://codeforces.com/contest/1200/problem/E
题意:
给你n个字符串,你需要按顺序连接这些字符串,如果当前的字符串的前缀和上一个字符串的后缀相同,则连接时要去掉当前字符串的前缀
思路:
一开始暴力,果断TLE,然后用kmp,还是TLE,改了几十次后发现是每次调用kmp和getnex时都调用用了strlen,增加了复杂度,去掉之后就AC了
为什么用kmp呢?因为kmp可以在文本串中找到模板串匹配的部分,现在要当前字符串的前缀匹配上一个字符串的后缀,我们就从上一个字符串的长度-当前字符串的长度的位置开始找,
因为一个字符串的前缀最长是他本身,所以当前字符串的前缀最多能匹配到这个位置(再往前当前字符串的长度就不够了),然后用kmp匹配,然后返回一个当前字符串的前缀与上一个字符串的后缀不匹配的位置(就是return j,j是当前字符串匹配的位置,如果t[i]==p[j]则j++,所以返回时j会指向不匹配的位置)
注意:
如果调用太多次strlen会TLE!!!
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int amn=1e6+5; 4 char ans[amn],in[amn]; 5 int n,nex[amn],len,tp; 6 void getnex(char in[]){ ///不要在这调用strlen!!!,用已有的就好了,不然会T到自闭!!! 7 nex[0]=nex[1]=0; 8 for(int i=1;i<len;i++){ 9 int j=nex[i]; 10 while(j&&in[i]!=in[j])j=nex[j]; 11 nex[i+1]=in[i]==in[j]?j+1:0; 12 } 13 } 14 int kmp(char t[],char p[],int pos){ ///不要在这调用strlen!!!,用已有的就好了,不然会T到自闭!!! 15 getnex(in); 16 int j=0; 17 for(int i=pos;i<tp;i++){ 18 while(j&&p[j]!=t[i])j=nex[j]; 19 if(p[j]==t[i])j++; 20 } 21 return j; 22 } 23 int main(){ 24 ios::sync_with_stdio(0); 25 cin>>n; 26 cin>>ans; 27 int pos; 28 tp=strlen(ans); ///注意,如果调用太多次strlen会TLE!!! 29 for(int i=2;i<=n;i++){ 30 cin>>in; 31 len=strlen(in); 32 pos=tp-len; ///上一个字符串的长度-当前字符串的长度,因为一个字符串的前缀最长是他本身,他最多只能匹配到这个位置 33 for(int j=kmp(ans,in,pos);j<len;j++) 34 ans[tp++]=in[j]; 35 } 36 for(int i=0;i<tp;i++) 37 printf("%c",ans[i]); 38 printf("\n"); 39 } 40 /** 41 给你n个字符串,你需要按顺序连接这些字符串,如果当前的字符串的前缀和上一个字符串的后缀相同,则连接时要去掉当前字符串的前缀 42 一开始暴力,果断TLE,然后用kmp,还是TLE,改了几十次后发现是每次调用kmp和getnex时都调用用了strlen,增加了复杂度,去掉之后就AC了 43 为什么用kmp呢?因为kmp可以在文本串中找到模板串匹配的部分,现在要当前字符串的前缀匹配上一个字符串的后缀,我们就从上一个字符串的长度-当前字符串的长度的位置开始找, 44 因为一个字符串的前缀最长是他本身,所以当前字符串的前缀最多能匹配到这个位置(再往前当前字符串的长度就不够了),然后用kmp匹配,然后返回一个当前字符串的前缀与上一个字符串的后缀不匹配的位置(就是return j,j是当前字符串匹配的位置,如果t[i]==p[j]则j++,所以返回时j会指向不匹配的位置) 45 然后从这个位置开始把当前字符串后面的字符都加到上一个字符串后面,知道输入完毕,最后输出ans就行了 46 注意:如果调用太多次strlen会TLE!!! 47 **/