CF1063F. String Journey

CF1063F. String Journey

https://codeforces.com/problemset/problem/1063/F

分析:

  • 一定存在一种最优解使得串的长度从\(ans\)开始递减到\(1\)
  • \(f_i\)表示以\(i\)开头的串到最后最多能走几次。
  • 那么从后往前转移,有\(f_i=f_j+1,f_j>=i+f_i,s[i...i+f_i-1]\supseteq s[j...j+f_i-2]\)
  • 注意到\(f_i\le f_{i+1}+1\),整个过程中不断check每个dp值是否合法的,最多check\(O(n)\)次。
  • 如何维护合法的\(j\)的集合,注意到\(i+f_i\)随着\(i\)减小而不增,因此\(j\)不增,双指针插入即可。
  • 由于\(f_j>f_i\)也算是合法的,我们其实是保证\(s[i...i+f_i-2]\)\(s[i+1...i+f_i-1]\)是某个\(s[j...j+f_j-1]\)的前缀。
  • 将字符串反过来用后缀树维护即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
using namespace std;
#define N 1000050
#define db(x) cerr<<#x<<" = "<<x<<endl
#define ls p<<1
#define rs p<<1|1
char w[N];
int ch[N][26],fa[N],len[N],lst=1,cnt=1,pos[N];
int head[N],to[N],nxt[N],tot;
int f[22][N],Lg[N],dp[N],ans,dfn[N],enp[N];
int mx[N<<2],n;
inline void add(int u,int v) {
	to[++tot]=v; nxt[tot]=head[u]; head[u]=tot;
}
void update(int l,int r,int x,int v,int p) {
	mx[p]=max(mx[p],v);if(l==r) return ;
	int mid=(l+r)>>1; if(x<=mid) update(l,mid,x,v,ls); else update(mid+1,r,x,v,rs);
}
int query(int l,int r,int x,int y,int p) {
	if(x<=l&&y>=r) return mx[p];
	int mid=(l+r)>>1,re=0;
	if(x<=mid) re=max(re,query(l,mid,x,y,ls));
	if(y>mid) re=max(re,query(mid+1,r,x,y,rs));
	return re;
}
void insert(int x,int id) {
	int p=lst,np=++cnt,q,nq;
	lst=np; len[np]=len[p]+1;
	for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
	if(!p) fa[np]=1;
	else {
		q=ch[p][x];
		if(len[q]==len[p]+1) fa[np]=q;
		else {
			nq=++cnt; fa[nq]=fa[q]; memcpy(ch[nq],ch[q],sizeof(ch[q]));
			fa[q]=fa[np]=nq; len[nq]=len[p]+1;
			for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
		}
	}
	pos[id]=lst;
}
void dfs(int x) {
	int i; dfn[x]=++dfn[0];
	f[0][x]=fa[x];
	for(i=1;(1<<i)<=cnt;i++) f[i][x]=f[i-1][f[i-1][x]];
	for(i=head[x];i;i=nxt[i]) {
		dfs(to[i]);
	}enp[x]=dfn[0];
}
int LEN;
int getp(int x,int d) {
	x=pos[x];
	int i;
	for(i=20;i>=0;i--) {
		if(f[i][x]&&len[f[i][x]]>=d) x=f[i][x];
	}return x;
}
bool check(int x,int d) {
	if(d==1) return 1;
	if(x-d+1<1) return 0;
	int p=getp(x,d-1);
	if(query(1,cnt,dfn[p],enp[p],1)>=d-1) return 1;
	p=getp(x-1,d-1);
	if(query(1,cnt,dfn[p],enp[p],1)>=d-1) return 1;
	return 0;
}
int main() {
	scanf("%d%s",&n,w+1);
	reverse(w+1,w+n+1);
	int i,j=n;
	for(i=1;i<=n;i++) insert(w[i]-'a',i);
	for(i=2;i<=cnt;i++) add(fa[i],i);
	dfs(1);
	LEN=0; while((1<<LEN)<=cnt)LEN++;
	for(i=1,j=0;i<=n;i++) {
		dp[i]=dp[i-1]+1;
		while(!check(i,dp[i])) {
			dp[i]--;
			j++;
			update(1,cnt,dfn[getp(j,dp[j])],dp[j],1);
		}
		ans=max(ans,dp[i]);
	}
	// for(i=n;i;i--) db(dp[i]);
	printf("%d\n",ans);

	return 0;
}
posted @ 2019-03-04 21:05  fcwww  阅读(412)  评论(0编辑  收藏  举报