从左到右依次把两个单词合并成一个单词。
合并两个单词的时候,要找到最大的i (i≥0),满足第一个单词的长度为 i 的后缀和第二个单词长度为 i 的前缀相等,然后把第二个单词第 i 位以后的部分接到第一个单词后面
请你输出最后合并后的单词。
分析
字符串 hash
对于答案串 res ,其后缀暴力枚举匹配 s[i] 的前缀
Code
字符串hash from 严格鸽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| const int maxn = 1000005; using ull = unsigned long long; string res;
struct str_hash{ ull base = 131; ull p[maxn]; char s[maxn]; unordered_map<ull,ull> hs; ull n;
void init(string &str){ n = str.size(); hs.clear(); for(int i = 1;i <= n;i++) s[i] = str[i-1]; p[0] = 1; for(int i = 1;i <= n;i++){ hs[i] = hs[i-1]*base+s[i]; p[i] = p[i-1] * base; } }
void add(string str){ for(auto c:str){ int i = ++n; hs[i] = hs[i-1]*base+c; p[i] = p[i-1]*base; } }
ull hash(int l,int r) { return hs[r] - hs[l-1]*p[r-l+1]; } ull pre(int i){ return hash(1,i); } ull suf(int i){ return hash(n-i+1,n); } }o,p;
signed main() { int n;cin>>n; vector<string> s(n+1); forr(i,1,n) cin >> s[i]; res = s[1]; o.init(res); forr(i,2,n){ p.init(s[i]); int len = min(o.n,(ull)s[i].size()); int j = 0; for(int k = 1;k <= len;k++){ if(o.suf(k) == p.pre(k)) j = k; } string t = s[i].substr(j); o.add(t); res += t; } cout << res << endl; return 0; }
|