zoukankan      html  css  js  c++  java
  • 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_ile 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
    ",ans);
    
    	return 0;
    }
    
  • 相关阅读:
    编写登陆认证程序
    Ubuntu18.04安装MySQL
    python输出的高亮显示
    河北省赛
    dp
    迷宫问题
    牛客-幸运数字Ⅱ
    [管理运筹学]线性规划&单纯形法的各种姿势(题目:[NOI2008]志愿者招募)
    [管理运筹学]指派问题的匈牙利算法及其c++实现 (例:「网络流 24 题」分配问题 )
    打算在CSDN写了,虽然博客园也很好
  • 原文地址:https://www.cnblogs.com/suika/p/10473182.html
Copyright © 2011-2022 走看看