• [洛谷P6640] BJOI2020 封印


    题目链接

    洛谷

    解析

    我们先给 (T) 串建一个后缀自动机,然后求出 (S) 中以每一个位置结尾的最长公共子串(设其长度为 (len_i))。这样问题就转变为对于区间 ([L,R]) 求最大的 (min(len_i,i-L+1)) 。发现这个 (min) 实在是不太好搞,我们转化一下,如果 (len_ile i-L+1) 就可以得到 (i-len_i+1ge L) 。而 (i-len_i+1) 是随着 (i) 的增大而不降的。因此我们可以通过二分找到一个位置 (pos) 使得 ([pos,R]) 中的 (i-len_i+1) 全都不小于 (L) 。二分和统计答案的过程可以用线段树维护。

    当然正确的写法是ST表,但是有O2

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 200002
    using namespace std;
    struct SAM{
    	int len,link,son[2];
    }a[N*2];
    struct SegmentTree{
    	int dat,len;
    }t[N*4];
    char S[N],T[N];
    int n,m,q,i,val[N],cnt,last;
    void extend(char c)
    {
    	int cur=++cnt,now=last,x=(int)(c-'a');
    	a[cur].len=a[now].len+1;
    	while(now!=-1&&!a[now].son[x]){
    		a[now].son[x]=cur;
    		now=a[now].link;
    	}
    	if(now==-1) a[cur].link=0;
    	else{
    		int p=now,q=a[p].son[x];
    		if(a[q].len==a[p].len+1) a[cur].link=q;
    		else{
    			int tmp=++cnt;
    			a[tmp]=a[q];
    			a[tmp].len=a[p].len+1;
    			a[q].link=a[cur].link=tmp;
    			while(p!=-1&&a[p].son[x]==q){
    				a[p].son[x]=tmp;
    				p=a[p].link;
    			}
    		}
    	}
    	last=cur;
    }
    void build(int p,int l,int r)
    {
    	if(l==r){
    		t[p].len=val[l];
    		t[p].dat=l-val[l]+1;
    		return;
    	}
    	int mid=(l+r)/2;
    	build(p*2,l,mid);build(p*2+1,mid+1,r);
    	t[p].len=max(t[p*2].len,t[p*2+1].len);
    	t[p].dat=min(t[p*2].dat,t[p*2+1].dat);
    }
    int ask1(int p,int l,int r,int ql,int qr)
    {
    	if(ql>qr) return 0;
    	if(ql<=l&&r<=qr) return t[p].len;
    	int mid=(l+r)/2,ans=0;
    	if(ql<=mid) ans=max(ans,ask1(p*2,l,mid,ql,qr));
    	if(qr>mid) ans=max(ans,ask1(p*2+1,mid+1,r,ql,qr));
    	return ans;
    }
    int ask2(int p,int l,int r,int ql,int qr)
    {
    	if(ql<=l&&r<=qr) return t[p].dat;
    	int mid=(l+r)/2,ans=1<<30;
    	if(ql<=mid) ans=min(ans,ask2(p*2,l,mid,ql,qr));
    	if(qr>mid) ans=min(ans,ask2(p*2+1,mid+1,r,ql,qr));
    	return ans;
    }
    int main()
    {
    	scanf("%s%s",S+1,T+1);
    	n=strlen(S+1);m=strlen(T+1);
    	a[0].link=-1;
    	for(i=1;i<=m;i++) extend(T[i]);
    	int v=0,l=0;
    	for(i=1;i<=n;i++){
    		int p=(int)(S[i]-'a');
    		while(v&&!a[v].son[p]) v=a[v].link,l=a[v].len;
    		if(a[v].son[p]) v=a[v].son[p],l++;
    		val[i]=l;
    	}
    	build(1,1,n);
    	scanf("%d",&q);
    	for(i=1;i<=q;i++){
    		int L,R;
    		scanf("%d%d",&L,&R);
    		int l=L,r=R,mid,pos=R+1;
    		while(l<=r){
    			mid=(l+r)/2;
    			if(ask2(1,1,n,mid,R)>=L) pos=mid,r=mid-1;
    			else l=mid+1;
    		}
    		printf("%d
    ",max(pos-L,ask1(1,1,n,pos,R)));
    	}
    	return 0;
    }
    
  • 相关阅读:
    绕口令系列 1
    毕业论文排版
    使用matlab表示“段数不确定”的分段函数
    [转]C/C++关于全局变量和局部变量初始化与不初始化的区别
    [转]基于Protel DXP软件的PCB高级编辑技巧大全
    冒泡排序及其优化
    gcc编译器参数
    [转]跟我一起写Makefile系列
    实例说明optimize table在优化mysql时很重要
    log4php0.9的详细配备实例说明
  • 原文地址:https://www.cnblogs.com/LSlzf/p/14337216.html
Copyright © 2020-2023  润新知