题意:
给定一行字符串,将其中相邻的有共同前后缀的子串进行合并,求和合并后最短的字符串
思路:
KMP
设第一个字符串为a,第二个字符串为b,如果a+b能够进行压缩,实际求b+a的最长的border(最长的公共前后缀长度),利用KMP可以做到这一点
每次把公共部分的前后缀长度求出后,将上一次的结果+除去前缀的当前字符串作为合并后新的字符串,重复n次即可
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
string ans,t;
ll Len,len1,len2,len,cnt;
int p[1000010];
ll KMP(string s){
int i=0,j=-1;
p[0]=-1;
while(i<=Len){
if(j==-1||s[i]==s[j])p[++i]=++j;
else j=p[j];
}
return p[Len];//返回最长的相同的前后缀
}
int main(){
ll n;
cin>>n;
cin>>ans;
len1=ans.length();
len2=0;cnt=0;
for(int i=1;i<n;i++){
cin>>t;
len1=len1+len2-cnt;//ans的长度
len2=t.size();//t的长度
len=min(len1,len2);//取最小长度
string s=t;
s+='#';//分割
s.insert(s.end(),ans.end()-len,ans.end());//拼接
Len=len2+1+len;//拼接后的长度
cnt=KMP(s);//最长的相同的前后缀
ans.insert(ans.end(),t.begin()+cnt,t.end());//去掉前缀拼接
}
cout<<ans<<endl;
return 0;
}
// /\ | / |**、
// / \ | / | \
// / \ |/ | / _____ ____ | /
// /------\ |\ |__/ / \ \ /\ / / \ | /
// / \ | \ | / \ \ / \ / /______\ |/
// / \ | \ | \ / \ / \ / \ |
// / \ | \ | \_____/ \/ \/ \_____ |
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
// warm heart, wagging tail,and a smile just for you!
//
// _ooOoo_
// o8888888o
// 88" . "88
// (| -_- |)
// O\ = /O
// ____/`---'\____
// .' \| |// `.
// / \||| : |||// \
// / _||||| -:- |||||- \
// | | \\ - /// | |
// | \_| ''\---/'' | |
// \ .-\__ `-` ___/-. /
// ___`. .' /--.--\ `. . __
// ."" '< `.___\_<|>_/___.' >'"".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `-. \_ __\ /__ _/ .-` / /
// ======`-.____`-.___\_____/___.-`____.-'======
// `=---='
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//