• BZOJ3796 Mushroom追妹纸 字符串 SA KMP


    原文链接https://www.cnblogs.com/zhouzhendong/p/9253173.html

    题目传送门 - BZOJ3796

    题意

      找一个串 $w$ 满足:

      1、$w$ 是 $s_1$ 的子串

      2、$w$ 是 $s_2$ 的子串

      3、$s_3$ 不是 $w$ 的子串

      4、$w$ 的长度应尽可能大

      输出 $w$ 的长度。

      $|s_1|,|s_2|leq 50000,|s_3|leq 10000$

    题解

      考虑求两个串 $(s_1,s_2)$ 的最长公共子串,我们可以把他们用一个特殊字符隔开,然后跑一下 $SA$ .。

      然后请你自行证明最长的一定是一个 $height[i]$ ,满足 $SA[i],SA[i-1]$ 这两个位置分别在 $s_1$ 和 $s_2$ 中。

      再考虑加上 $s_3$ 的限制。

      我们 $KMP$ 一下,看看从哪些位置开始,$s_3$ 与由 $s_1,s_2$ 构成的母串重合。

      然后预处理出对于母串的每一个位置,下一个重合点最早出现在哪里,记为 $e[i]$ ,于是从当前位置开始的串长不能超过 $e[i]-i+|s_3|-1$ ,最后统计 $height$ 的时候取个 $min$ 即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=200005;
    int m,n,l,fail[N],e[N];
    int SA[N],tmp[N],rank[N],height[N],tax[N];
    char s[N],t[N];
    void KMP(){
    	fail[0]=0,fail[1]=0;
    	for (int i=2;i<=l;i++){
    		int f=fail[i-1];
    		while (f>0&&t[f+1]!=t[i])
    			f=fail[f];
    		fail[i]=f+(t[f+1]==t[i]);
    	}
    	int k=0;
    	for (int i=1;i<=n;i++){
    		while (k>0&&t[k+1]!=s[i])
    			k=fail[k];
    		k+=(t[k+1]==s[i]);
    		if (k==l)
    			k=fail[k],e[i-l+1]=i-l+1;
    	}
    }
    void Sort(int n,int m){
    	for (int i=0;i<=m;i++)
    		tax[i]=0;
    	for (int i=1;i<=n;i++)
    		tax[rank[i]]++;
    	for (int i=1;i<=m;i++)
    		tax[i]+=tax[i-1];
    	for (int i=n;i>=1;i--)
    		SA[tax[rank[tmp[i]]]--]=tmp[i];
    }
    bool cmp(int rk[],int x,int y,int w){
    	return rk[x]==rk[y]&&rk[x+w]==rk[y+w];
    }
    void Suffix_Array(char s[],int n){
    	memset(SA,0,sizeof SA);
    	memset(tmp,0,sizeof tmp);
    	memset(rank,0,sizeof rank);
    	memset(height,0,sizeof height);
    	int m=200;
    	for (int i=1;i<=n;i++)
    		rank[i]=s[i],tmp[i]=i;
    	Sort(n,m);
    	for (int w=1,p=0;p<n;w<<=1,m=p){
    		p=0;
    		for (int i=n-w+1;i<=n;i++)
    			tmp[++p]=i;
    		for (int i=1;i<=n;i++)
    			if (SA[i]>w)
    				tmp[++p]=SA[i]-w;
    		Sort(n,m);
    		swap(tmp,rank);
    		rank[SA[1]]=p=1;
    		for (int i=2;i<=n;i++)
    			rank[SA[i]]=cmp(tmp,SA[i],SA[i-1],w)?p:++p;
    	}
    	for (int i=1,j,k=0;i<=n;height[rank[i++]]=k)
    		for (k=max(k-1,0),j=SA[rank[i]-1];s[i+k]==s[j+k];k++);
    	height[1]=0;
    }
    bool Type(int x){
    	return x>m;
    }
    int main(){
    	scanf("%s",s+1);
    	m=strlen(s+1)+1;
    	s[m]='*';
    	scanf("%s",s+m+1);
    	n=strlen(s+1);
    	scanf("%s",t+1);
    	l=strlen(t+1);
    	for (int i=1;i<=n;i++)
    		e[i]=n+1;
    	KMP();
    	for (int i=n-1;i>=1;i--)
    		e[i]=min(e[i],e[i+1]);
    	Suffix_Array(s,n);
    	int ans=0;
    	for (int i=2;i<=n;i++)
    		if (Type(SA[i])^Type(SA[i-1]))
    			ans=max(ans,min(height[i],e[SA[i]]-SA[i]+l-1));
    	printf("%d",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    【WF2017】Mission Improbable
    【Codeforces 837D】Round Subset
    【Codeforces 788C】The Great Mixing
    【JSOI2008】最大数
    2.1图像的数字化
    MATLAB生成随机数
    四六级准考证号忘记了如何快速查询四六级成绩?
    加密与水印结合
    如何在 PyPI安装python的软件包?
    matlab中如何定义函数
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ3796.html
Copyright © 2020-2023  润新知