CF1200E Compress Words
题意:
题目意思不难理解。从左到右依次合并字符串。
思路:
KMP。每输入一个新的字符串,就用这个新的字符串与当前的答案串进行匹配。由于这道题只需要考虑两个字符串前后缀相匹配的情况,因此不需要从头开始匹配。如果当前的答案串是s,模式串是t,从max(0,slen-tlen)处开始匹配即可。
用一个KMP的模板就顺利解决啦!
。。。。。。。。。。。。(并没有)
嗯,其实关于这道题我想说的不是思路。我用上述思路写出来之后,不知道为什么,一直TLE在第三个测试点。复杂度,求nexts数组是O(lent),kmp匹配,由于不需要从头匹配,复杂度也是O(lent),这么算下来整个复杂度是O(total length) 最多也是1e6。我检查了很久,一度怀疑是不是我的板子出了问题。
这个是我当时用的板子,看起来没什么问题是不是。
int KMP_search(string s,string p){ int slen=s.size(); int plen=p.size(); int i,j=0; i=max(0,slen-plen); while(i<slen){ if(j==-1||s[i]==p[j]) ++i,++j; else j=nexts[j]; } return j; } void get_next(string p,int nexts[]){ int j=0,k=-1; nexts[0]=-1; int plen=p.size(); while(j<plen-1){ if (k==-1||p[k]==p[j]){ j++,k++,nexts[j]=k; } else k=nexts[k]; } }
直到后来,我在CF上翻到了这道题的一个提问帖。这个提问的人也是卡在了第三个测试点,不过他用的是Hash,代码我就不贴出来了。总之,我在下面看到了这样一条回答:
这位大神的回答包括三点:1.函数中包含string类的参数时,最好用引用(reference)或者干脆用全局变量,函数也最好是void类型的。这是因为多次拷贝和返回string类型的变量很费时。2.用a+=b[i]代替a=a+b[i] 3.多次创建hash类型的数组。
于是,当我把函数中string类的参数都改成了引用后:
这个困扰了我两天的问题就这样解决了。。。。。。
说实话,挺让我意外的,我是真没想到居然是这种问题,之前一直没有在意过。最大的收获就是函数中的参数也是有讲究的,最好是指针,引用,或者直接全局变量。
最后奉上我的AC代码 以及 文中的求助帖链接:https://codeforces.ml/blog/entry/75139
AC代码
#include <bits/stdc++.h> using namespace std; const int MAXN=1e6+10; int nexts[MAXN]; string s1,s2; int KMP_search(string &s,string &p){ int slen=s.size(); int plen=p.size(); int i,j=0; i=max(0,slen-plen); while(i<slen){ if(j==-1||s[i]==p[j]) ++i,++j; else j=nexts[j]; } return j; } void get_next(string &p){ int j=0,k=-1; nexts[0]=-1; int plen=p.size(); while(j<plen-1){ if (k==-1||p[k]==p[j]){ j++,k++,nexts[j]=k; } else k=nexts[k]; } } int main() { int n;cin>>n; cin>>s1; for (int i=2;i<=n;i++) { cin>>s2; get_next(s2); int m=KMP_search(s1,s2); s1+=s2.substr(m); } cout<<s1; return 0; }