CF1200E 题解

这题从头到脚都散发着均摊(暴力)的气息 qwq


题意就是输入很多 (\(\leq 10^5\))串, 维护一个 \(ans\) 串, 起始时 \(ans\) 串为空, 每输入一个串就要和 \(ans\) 串合并, 合并时将输入的串的最长的和 \(ans\) 串的某一后缀相等的前缀去掉, 然后把剩下部分接到 \(ans\) 串的后面。
输入串的总长不超过 \(10^6\)


如果每次都暴力地将整个 \(ans\) 串和输入串用 \(kmp\) 合并, 复杂度就成了 \(O(可以被卡)\)
但是如果注意到去掉的输入串的前缀长度不会超过输入串的总长, 每次只截取 \(ans\) 的一段长为输入串长度的后缀与输入串暴力合并, 复杂度就成了均摊 \(O(输入串总长)\),似乎快的一批。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 15;

int n, ansl;
char s[maxn], ans[maxn], tmp[maxn];
int nxt[maxn];
int main()
{
	cin>>n;
	scanf("%s", ans+1);
	ansl = strlen(ans+1);
	--n;
	while(n--) {
		scanf("%s", s+1);
		int sl = strlen(s+1);
		int tmpl = min(sl,ansl);
		for(int i=1;i<=tmpl;++i) tmp[i] = s[i];
		for(int i=1;i<=tmpl;++i) tmp[tmpl+i] = ans[ansl-tmpl+i];
		tmpl<<=1;
		nxt[1]=0;
		for(int i=2,j=0;i<=tmpl;++i) {
			while(j&&tmp[j+1]!=tmp[i]) j=nxt[j];
			if(tmp[j+1]==tmp[i]) ++j;
			nxt[i]=j;
		}
		int mxpl = nxt[tmpl];
		while(mxpl>tmpl/2) mxpl = nxt[mxpl];
		int deltal = sl-mxpl;
		for(int i=1;i<=deltal;++i) ans[ansl+i] = s[mxpl+i];
		ansl += deltal;
	}
	for(int i=1;i<=ansl;++i) putchar(ans[i]);
	return 0;
}
posted @ 2020-04-29 07:08  xwmwr  阅读(204)  评论(1编辑  收藏  举报