BZOJ2534 Uva10829L-gap字符串 字符串 SA ST表

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

题目传送门 - BZOJ2534

题意

  有一种形如 $uvu$ 形式的字符串,其中 $u$ 是非空字符串,且 $V$ 的长度正好为 $L$ ,那么称这个字符串为 $L-Gap$ 字符串。

  给出一个字符串 $S$ ,以及一个正整数 $L$ ,问 $S$ 中有多少个 $L-Gap$ 子串。

  $L< |S|\leq 5\times 10^4$

题解

  我甚至怀疑写这题题解是否必要……

  这题和BZOJ2119简直一毛一样啊。

BZOJ2119 股市的预测 字符串 SA ST表

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
int n,m,tot=0,a[N];
char s[N];
map <int,int> mp;
int SA[N],rank[N],tmp[N],height[N],tax[N];
int ST[N][20];
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(int s[],int n){
	memset(SA,0,sizeof SA);
	memset(tmp,0,sizeof tmp);
	memset(rank,0,sizeof rank);
	memset(height,0,sizeof height);
	for (int i=1;i<=n;i++)
		rank[i]=s[i],tmp[i]=i;
	int m=234;
	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(rank,tmp);
		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;
}
void Get_ST(int n){
	memset(ST,0,sizeof ST);
	for (int i=1;i<=n;i++){
		ST[i][0]=height[i];
		for (int j=1;j<20;j++){
			ST[i][j]=ST[i][j-1];
			if (i-(1<<(j-1))>0)
				ST[i][j]=min(ST[i][j],ST[i-(1<<(j-1))][j-1]);
		}
	}
}
int Query(int L,int R){
	int val=floor(log(R-L+1)/log(2));
	return min(ST[L+(1<<val)-1][val],ST[R][val]);
}
int LCP(int x,int y){
	x=rank[x],y=rank[y];
	return Query(min(x,y)+1,max(x,y));
}
int LCS(int x,int y){
	return LCP(n*2+2-x,n*2+2-y);
}
int main(){
	scanf("%d",&m);
	scanf("%s",s+1);
	n=strlen(s+1);
	for (int i=1;i<=n;i++)
		a[i]=a[n*2+2-i]=s[i];
	a[n+1]=233;
	Suffix_Array(a,n*2+1);
	Get_ST(n*2+1);
	LL ans=0;
	for (int L=1;L<=n;L++)
		for (int i=1;i+L+m<=n;i+=L){
			int x=i,y=i+L+m;
			int lcp=min(LCP(x,y),L),lcs=min(LCS(x,y),L);
			int len=lcp+lcs-(lcp>0&&lcs>0);
			ans+=max(len-L+1,0);
		}
	printf("%lld\n",ans);
	return 0;
}

  

 

posted @ 2018-06-28 21:04  zzd233  阅读(395)  评论(0编辑  收藏  举报