Codeforces Round #578 (Div. 2) E.Compress Words

1 篇文章 0 订阅

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(1n105), 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 pizza

Sample 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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值