codeforces 427 D Match & Catch ( 后缀数组 )

来源:互联网 发布:手机淘宝换回默认皮肤 编辑:程序博客网 时间:2024/05/16 13:03

题意 : 给你两个字符串 , 找到其中最短的字符串,要求在串1中出现过,在串2中出现过,并且在串1中只出现过一次,在串2中只出现过一次

思路 : 将两个串拼接在一起 , 用 $ 隔开 。 我们根据 height 数组求解。

首先 , 我们要求解的字符串必然是两个串的公共子串 , 所以对于 height[i] 应该要保证 sa[i-1] 和 sa[i] 分别处于两个字符串。( 我们只用考虑后缀排序后相连的情况 , 因为如果两个后缀在sa中不相连,那么中间必然两个字符串的LCP大于这两个字符串的LCP,那么就不能保证这个字符串在两个串中只出现一次了 )

当然这样只是求得两个串的公共子串,要判断是否满足题意,那么就要判断height[i-1] 和 height[i+1] , 只有这两个最大值要小于 height[i] , height[i] 这个字符串才满足题意。否则必然在串1或者串2中出现过该串。

当然了这样求得的字符串不能保证是最短的。对于一个height[i] , 我们取的最小值应该是 max( height[i-1] , height[i+1] ) + 1 . 因为 max( height[i-1] ,height[i+1] ) 就是和其他后缀的最大LCP,那么加1之后就能保证是唯一的。

那么对于每个符合题意的height[i] 取个最小值即可。这样如果用dc3,就是O(n)的复杂度了 。

#include <stdio.h>    #include <string.h>  #include <string>  #include <vector>  #include <iostream>  #include <algorithm>    using namespace std;      #define INF 0x3f3f3f3f  #define maxn 10005  int wa[maxn],wb[maxn],wv[maxn],wt[maxn];      typedef long long LL ;    int cmp(int *r,int a,int b,int l)    {return r[a]==r[b]&&r[a+l]==r[b+l];}      void da(int *r,int *sa,int n,int m){        int i,j,p,*x=wa,*y=wb,*t;        for(i=0;i<m;i++) wt[i]=0;        for(i=0;i<n;i++) wt[x[i]=r[i]]++;        for(i=1;i<m;i++) wt[i]+=wt[i-1];        for(i=n-1;i>=0;i--) sa[--wt[x[i]]]=i;        for(j=1,p=1;p<n;j*=2,m=p){            for(p=0,i=n-j;i<n;i++) y[p++]=i;            for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;            for(i=0;i<n;i++) wv[i]=x[y[i]];            for(i=0;i<m;i++) wt[i]=0;            for(i=0;i<n;i++) wt[wv[i]]++;            for(i=1;i<m;i++) wt[i]+=wt[i-1];            for(i=n-1;i>=0;i--) sa[--wt[wv[i]]]=y[i];            for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;        }    }      int Rank[maxn],height[maxn];      void calheight(int *r,int *sa,int n){        int i , j , k = 0 ;        for( i=1 ; i<=n ; i++ ) Rank[sa[i]]=i;        for(i=0;i<n;i++) {            if(k)k--;            int j = sa[Rank[i]-1];            while(r[i+k]==r[j+k]) k++ ;            height[Rank[i]] = k ;        }           return;    }char str[maxn] ;int r[maxn] , sa[maxn] ; int main(){while( scanf( "%s" , str ) != EOF ) {int l1 = strlen( str ) ;str[l1] = '$' ;str[l1+1] = 0 ;scanf( "%s" , str + l1 + 1 ) ;int len = strlen( str ) ;for( int i = 0 ; i < len ; i ++ ) r[i] = str[i] ;r[len] = 0 ;da( r , sa , len + 1 , 200 ) ;calheight( r , sa , len ) ;int Min = INF ;for( int i = 2 ; i <= len ; i ++ ) {if( ( sa[i-1] - l1 ) * ( sa[i] - l1 ) < 0 && height[i] ) {bool flag = true ;int Max = 0 ;if( height[i-1] >= height[i] ) {flag = false ;}elseMax = max( Max , height[i-1] ) ;if( i < len && height[i+1] >= height[i] ) {flag = false ;}elseMax = max( Max , height[i+1] ) ;if( flag ) {Min = min( Min ,  Max + 1 ) ;}}}if( Min == INF  ){puts( "-1" ) ;} else {  printf( "%d\n" , Min ) ;}}return 0 ;}


0 0
原创粉丝点击