[kmp,不要过多调用strlen!!!] Codeforces 1200E Compress Words

题目:http://codeforces.com/contest/1200/problem/E

Compress Words
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Amugae has a sentence consisting of nn words. He want to compress this sentence into one word. Amugae doesn't like repetitions, so when he merges two words into one word, he removes the longest prefix of the second word that coincides with a suffix of the first word. For example, he merges "sample" and "please" into "samplease".

Amugae will merge his sentence left to right (i.e. first merge the first two words, then merge the result with the third word and so on). Write a program that prints the compressed word after the merging process ends.

Input

The first line contains an integer nn (1n1051≤n≤105), the number of the words in Amugae's sentence.

The second line contains nn words separated by single space. Each words is non-empty and consists of uppercase and lowercase English letters and digits ('A', 'B', ..., 'Z', 'a', 'b', ..., 'z', '0', '1', ..., '9'). The total length of the words does not exceed 106106.

Output

In the only line output the compressed word after the merging process ends as described in the problem.

Examples
input
Copy
5
I want to order pizza
output
Copy
Iwantorderpizza
input
Copy
5
sample please ease in out
output
Copy
sampleaseinout

题意:

给你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 **/

 

posted @ 2019-08-28 19:13  Railgun000  阅读(228)  评论(0编辑  收藏  举报