[TJOI2017]DNA——后缀数组求LCP

题目大意:

给定一个文本串和一个模式串,求文本串中有多少个连续的子串和模式串相差不超过三个字符。

思路:

算是一道后缀数组的模板题。

直接做lcp,然后遇到匹配不上的就跳,跳的次数不能超过三次。

具体地,将两个字符串连在一起,中间加一个分隔符,然后求出height,用rmq维护height数组的区间最小值即可。

/*=======================================
 * Author : ylsoi
 * Time : 2019.2.5
 * Problem : luogu3763
 * E-mail : ylsoi@foxmail.com
 * ====================================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
    freopen("luogu3763.in","r",stdin);
    freopen("luogu3763.out","w",stdout);
}

template<typename T>void read(T &_){
	_=0; T fl=1; char ch=getchar();
	for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
	for(;isdigit(ch);ch=getchar())_=(_<<1)+(_<<3)+(ch^'0');
	_*=fl;
}

const int maxn=2e5+10;
int T;
int n,m;
char s[maxn];
int sz,sa[maxn],tp[maxn],rk[maxn],tax[maxn],height[maxn];
int st[maxn][21],Log[maxn];

void radix_sort(){
	REP(i,1,sz)tax[i]=0;
	REP(i,1,n)++tax[rk[i]];
	REP(i,1,sz)tax[i]+=tax[i-1];
	DREP(i,n,1)sa[tax[rk[tp[i]]]--]=tp[i];
}

void suffix_sort(){
	sz=26;
	REP(i,1,n)rk[i]=s[i]-'A'+1,tp[i]=i;
	radix_sort();
	for(int w=1,p=0;w<n;w<<=1){
		p=0;
		REP(i,1,w)tp[++p]=n-w+i;
		REP(i,1,n)if(sa[i]>w)tp[++p]=sa[i]-w;
		radix_sort();
		swap(rk,tp);
		rk[sa[1]]=p=1;
		REP(i,2,n)
			if(tp[sa[i-1]]==tp[sa[i]] && tp[sa[i-1]+w]==tp[sa[i]+w])rk[sa[i]]=p;
			else rk[sa[i]]=++p;
		sz=p;
		if(sz==n)break;
	}
}

void get_height(){
	int k=0;
	REP(i,1,n){
		if(k)--k;
		int j=sa[rk[i]-1];
		while(s[i+k]==s[j+k])++k;
		height[rk[i]]=k;
	}
}

void init_st(){
	REP(i,1,n)st[i][0]=height[i];
	REP(j,1,Log[n])REP(i,1,n-(1<<j)+1)
		st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

int lcp(int x,int y){
	x=rk[x],y=rk[y];
	if(x>y)swap(x,y);
	++x;
	int d=Log[y-x+1];
	return min(st[x][d],st[y-(1<<d)+1][d]);
}

int main(){
	File();
	REP(i,2,2e5)Log[i]=Log[i>>1]+1;
	read(T);
	while(T--){
		scanf("%s",s+1);
		m=strlen(s+1)+1;
		s[m]='Z';
		scanf("%s",s+m+1);
		n=strlen(s+1);
		suffix_sort();
		get_height();
		init_st();
		int ans=0;
		REP(i,1,m-n+m){
			int p=0,len;
			REP(j,1,4){
				len=lcp(i+p,m+1+p);
				p+=len;
				if(p==n-m){++ans; break;}
				else ++p;
			}
		}
		printf("%d
",ans);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/ylsoi/p/10353533.html