E.Compress Words
题目链接: https://codeforces.com/contest/1200/problem/E
Problem Description
Amugae has a sentence consisting of n n n 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 n ( 1 ≤ n ≤ 1 0 5 ) n (1≤n≤10^5) n(1≤n≤105), the number of the words in Amugae’s sentence.
The second line contains n n n 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 1 0 6 10^6 106.Output
In the only line output the compressed word after the merging process ends as described in the problem.
Sample Input
5
I want to order pizzaSample Output
Iwantorderpizza
题意
给出 n n n个仅由’A’ ~ ‘Z’,‘a’ ~ ‘z’,‘0’ ~ '9’组成的字符串依次从左往右合并。
合并的时候上一个合并好的字符串 p r e pre pre和当前字符串 s t r str str要除去一份最长公共的 p r e pre pre后缀和 s t r str str前缀。
例如 p r e pre pre为"sample", s t r str str为"please",两者合并后消除一份公共的"ple",所以合并后的字符串为"samplease"。
思路
设上一个合并好的字符串为 p r e pre pre,当前字符串为 s t r str str,取 l e n = m i n ( ∣ p r e ∣ , ∣ s t r ∣ ) len = min(|pre|,\ |str|) len=min(∣pre∣, ∣str∣),在 s t r str str中取长度为 l e n len len的前缀, p r e pre pre中取长度为 l e n len len的后缀构成字符串 c c c。
此时问题就转换为求 c c c的最长相同前缀后缀了。是不是想到了 k m p kmp kmp中的 N e x t Next Next数组,但并不是完全一样,因为这个是有限制的,即前缀要属于 s t r str str的前缀,后缀要属于 p r e pre pre的后缀,(j && j>=len_c/2)
正是保证所匹配的前缀是属于 s t r str str中的,最后Next[len_c]
就是最长的相同前缀后缀了。
代码
#include <bits/stdc++.h>
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
#define esp 1e-9
#define inf 0x3f3f3f3f
#define inff 0x3f3f3f3f3f3f3f3f
#define Pair pair<ll, ll>
#define It list<node>::iterator
using namespace std;
const ll N = 1e6+5;
string a, b, c;
ll n, len_a, len_b, Next[N];
ll get_next(){//计算Next数组
ll ans = 0, len_c = c.length();
Next[1] = 0;
for (ll i = 1; i < len_c; i++){
ll j = Next[i];
while (j && j>=len_c/2){//保证匹配的前缀属于当前需要合并字符串的前缀
j = Next[j];
}
while (j && c[j]!=c[i]){
j = Next[j];
}
Next[i+1] = ((c[j]==c[i]) ? j+1 : 0);
}
return Next[len_c];
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>a;
n--;
while (n--){
cin>>b;
c = "";
len_a = a.length();
len_b = b.length();
//计算字符串c
if (len_a >= len_b){
c += b;
for (ll i = len_a-len_b; i < len_a; i++){
c += a[i];
}
}
else{
for (ll i = 0; i < len_a; i++){
c += b[i];
}
c += a;
}
ll len = get_next();//最长相同前缀后缀长度
for (ll i = len; i < len_b; i++){//更新pre
a += b[i];
}
}
cout<<a<<endl;
return 0;
}