zoukankan      html  css  js  c++  java
  • ●BZOJ 3796 Mushroom追妹纸

    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=3796

    题解:


    题意:
        给出三个串 A,B,C
        找出一个最长串 S,
        使得 S是A,B 的子串,但是 C不是S的子串。
     



    首先,对于第一二个限制,只需要把 A,B串用一个分隔符连接在一起。
    求出sa[],rank[],height[]数组,
    那么在排好序的后缀中,相邻的两个后缀如果一个属于A串(令在A串p位置),另一个属于B串的话,
    则可能贡献答案。 但应该贡献多少呢?
    由于有 C 的限制,即在LCP中选出的最长前缀里不能出现 C串。
    所以考虑如下做法。
    定义 appear[i] 表示 A串的 i位置后面第一次出现 C串的开始位置。
    求出这个以后,那么就可以贡献答案了:
    ANS=max(ANS,min(hei[i],appear[i]-p+LenC-1))
    以下是求pre数组的做法:
    把 A串作为文本串,C串作为匹配串,用 KMP去匹配。
    并在 A串中每一个出现 C串的开始位置打上标记
    然后反向跑一边,得出appear[]数组。

    总的复杂度 (Nlog2N+N)

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 100500
    #define INF 0x3f3f3f3f
    #define filein(x) freopen(#x".in","r",stdin);
    #define fileout(x) freopen(#x".out","w",stdout);
    using namespace std;
    char S[MAXN],A[MAXN],B[MAXN],C[MAXN];
    int sa[MAXN],rak[MAXN],hei[MAXN],app[MAXN];
    int L1,L2,L3,ANS;
    void build(int N,int M){
    	static int cc[MAXN],ta[MAXN],tb[MAXN],*x,*y,h,p;
    	x=ta; y=tb; h=0;
    	for(int i=0;i<M;i++) cc[i]=0;
    	for(int i=0;i<N;i++) cc[x[i]=S[i]]++;
    	for(int i=1;i<M;i++) cc[i]+=cc[i-1];
    	for(int i=N-1;i>=0;i--) sa[--cc[x[i]]]=i;
    	for(int k=1;p=0,k<N;k<<=1){
    		for(int i=N-k;i<N;i++) y[p++]=i;
    		for(int i=0;i<N;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
    		for(int i=0;i<M;i++) cc[i]=0;
    		for(int i=0;i<N;i++) cc[x[y[i]]]++;
    		for(int i=1;i<M;i++) cc[i]+=cc[i-1];
    		for(int i=N-1;i>=0;i--) sa[--cc[x[y[i]]]]=y[i];
    		swap(x,y); y[N]=-1; x[sa[0]]=0; M=1;
    		for(int i=1;i<N;i++)
    			x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?M-1:M++;
    		if(M>=N) break;
    	}
    	for(int i=0;i<N;i++) rak[sa[i]]=i;
    	for(int i=0,j;i<N;i++){
    		if(h) h--;
    		if(rak[i]){
    			j=sa[rak[i]-1];
    			while(S[i+h]==S[j+h]) h++;
    		}
    		hei[rak[i]]=h;
    	}
    }
    void KMP(char *T,char *S){
    	static int nxt[MAXN],i,j,k,lT,lS;
    	memset(app,0x3f,sizeof(app));
    	nxt[0]=-1; lT=strlen(T); lS=strlen(S);
    	j=0; k=-1;
    	while(j<lS){
    		if(k==-1||S[j]==S[k]) j++,k++,nxt[j]=k;
    		else k=nxt[k];
    	}
    	i=0; j=0;
    	while(i<lT){
    		if(j==-1||T[i]==S[j]){
    			i++; j++;
    			if(!S[j]) app[i-lS]=i-lS;
    		}
    		else j=nxt[j];
    	}
    	for(int i=lT-1;i>=0;i--) app[i]=min(app[i],app[i+1]);
    }
    bool bel(int p){
    	if(p<L1) return 0;
    	else return 1;
    }
    int main()
    {
    	int N;
    	scanf(" %s %s %s",A,B,C);
    	L1=strlen(A); L2=strlen(B); L3=strlen(C); N=L1+L2+1;
    	for(int i=0;i<L1;i++) S[i]=A[i]; S[L1]='&';
    	for(int i=0;i<L2;i++) S[L1+i+1]=B[i]; S[N]=0;
    	build(N,300);
    	KMP(A,C);
    	for(int i=1,p,q;i<N;i++){
    		if(hei[i]<=ANS||!(bel(sa[i-1])^bel(sa[i]))) continue;
    		if(!bel(sa[i-1])) p=sa[i-1]; else p=sa[i]; q=app[p];
    		ANS=max(ANS,min(hei[i],q-p+L3-1));
    	}
    	printf("%d",ANS);
    	return 0;
    }
    

  • 相关阅读:
    关于虚拟机断电导致的 generating /run/initramfs/rdsosreport.txt 问题优秀解决方案
    centos7 yum 阿里源
    startup.bat脚本启动tomcat时,cmd命令窗口闪现问题及Neither the JAVA_HOME nor the JRE_HOME environment variable is defined 错误解决
    Linux 中 Fish Shell
    卸载mysql
    /bin/bash^M: 坏的解释器: 没有那个文件或目录
    elementUI 文本鼠标移入显示太长
    el-upload 手动上传文件
    vue-element-admin 打包测试环境报错
    vue 分页跳转页面详情,返回记住当前点击第几页
  • 原文地址:https://www.cnblogs.com/zj75211/p/7994001.html
Copyright © 2011-2022 走看看