题目链接:点击这里
题目大意:
给定
n
n
n 个字符串,求
n
n
n 个字符串按序拼接好后的字符串,拼接规则为找到最大的
i
(
i
≥
0
)
i(i\ge 0)
i(i≥0) ,满足第一个单词的长度为ii的后缀和第二个单词长度为
i
i
i 的前缀相等,然后把第二个单词第ii位以后的部分接到第一个单词后面。输出最后那个单词
题目分析:
最长公共前后缀不难想到
K
M
P
KMP
KMP ,我们发现如果想合并
a
a
a 串和
b
b
b 串,只需要构造一个
b
,
a
b,a
b,a 的串即可,对这个串求一下
n
e
x
t
next
next 数组,然后最后一位的
n
e
x
t
next
next 数组值就是最长公共前后缀的长度,然后模拟合并即可。
但是事情似乎没有那么简单,我们发现,如果直接这么做是会超时,因为我如果一开始的串很长,后面的串又很短就会发现这个方法的复杂度是
O
(
n
2
)
O(n^2)
O(n2) 的。考虑如何优化,因为我们对很多不必要的位置跑了求
n
e
x
t
next
next ,所以我们限定一下原串与新串合并时合并的范围就可以了。
这时你就会发现不超时了,但
WA
\text{WA}
WA 了,这是因为比如合并
101
101
101 和
010
010
010 这两个串时,新组合的串为
010101
010101
010101 最后一位的
n
e
x
t
next
next 数组值大于单个串长了;这时我们只需要将两个串中间插入一个不可能存在的字符串即可将两个串阻断,防止这种情况发生
注意好了上述问题,这道题就可以顺利
a
c
ac
ac 了
具体细节见代码:
// Problem: Compress Words
// Contest: Virtual Judge - CodeForces
// URL: https://vjudge.net/problem/CodeForces-1200E
// Memory Limit: 262 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
//#define int ll
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 1e6+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,nxt[maxn];
string s,t;
void get_next(string s)
{
int n = s.size();
s = " "+s;
for(int i = 2,j = 0;i <= n;i++)
{
while(j && s[i]!=s[j+1]) j = nxt[j];
if(s[i] == s[j+1]) j++;
nxt[i] = j;
}
}
int main()
{
n = read();
cin>>s;
for(int i = 2;i <= n;i++)
{
cin>>t;
int len = min(t.size(),s.size());
string ss = t+"###"+s.substr(s.size()-len);
get_next(ss);
for(int j = nxt[ss.size()];j < t.size();j++) s += t[j];
}
cout<<s<<endl;
return 0;
}