后缀数组+调和级数--bzoj2119: 股市的预测

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/85275910

传送门

其实就是复杂度是调和级数…

首先差分一下就变成了找到形如 a b a aba 的串的个数,暴力求的话就是 n 2 l o g n n^2logn 的,可以枚举 a a 的长度,然后把串分成一段一段的,只计算每段的第一个点,从第一个点 l l 找到对应的 r = l + l e n + m r=l+len+m ,然后看 l , r l,r 能同时向左右延伸到哪里,也就是后缀 l c p lcp 和反串后缀 l c p lcp ,和 l e n len m i n min ,代表这个区间内长度为 l e n len 的串都是合法的串,然后答案加上两个 l c p lcp 的和再减去 l e n len 就好了,复杂度就是调和级数, n l o g n nlogn

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 100005
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;

inline int rd(){
	int x=0,f=1;char c=getchar();
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}
inline int min(int x,int y){return x<y?x:y;}

int n,m,K,s[N],a[N],tot;
int sa[N],rk[N],tp[N],tax[N],h[N],st[N][20];
LL ans;

inline void rsort(){
	for(int i=0;i<=m;i++) tax[i]=0;
	for(int i=1;i<=n;i++) tax[rk[i]]++;
	for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
	for(int i=n;i;i--) sa[tax[rk[tp[i]]]--]=tp[i];
}

inline void ssort(){
	for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
	rsort();
	for(int w=1,p=0;p<n&&w<=n;w<<=1,m=p){
		p=0;
		for(int i=n-w+1;i<=n;i++) tp[++p]=i;
		for(int i=1;i<=n;i++)
			if(sa[i]>w) tp[++p]=sa[i]-w;
		rsort(); swap(rk,tp);
		rk[sa[1]]=p=1;
		for(int i=2;i<=n;i++)
			if(tp[sa[i]]==tp[sa[i-1]] && tp[min(n+1,sa[i]+w)]==tp[min(n+1,sa[i-1]+w)])
				rk[sa[i]]=p;
			else rk[sa[i]]=++p;
	}
}

inline void get_h(){
	int k=0,j;
	for(int i=1;i<=n;i++){
		if(k) --k;
		j=sa[rk[i]-1];
		while(s[j+k]==s[i+k]) ++k;
		h[rk[i]]=k;
	}
}

inline void prework(){
	for(int i=1;i<=n;i++) st[i][0]=h[i];
	for(int j=1;(1<<j)<=n;j++)
		for(int i=1;i+(1<<j)-1<=n;i++)
			st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

inline int lcp(int l,int r){
	if(l>r) swap(l,r); ++l;
	int k=log2(r-l+1);
	return min(st[l][k],st[r-(1<<k)+1][k]);
}

inline void solve(){
	int r,len1,len2,len;
	for(int i=1;i+i+K<=tot;i++)
		for(int l=1;l+i+K<=tot;l+=i){
			r=l+i+K;
			len1=min(i,lcp(rk[l],rk[r]));
			len2=min(i,lcp(rk[n-l+1],rk[n-r+1]));
			if(len1+len2>=i) ans+=len1+len2-i;
		}
}

int main(){
	n=rd(); K=rd();
	for(int i=1;i<=n;i++) s[i]=rd(); --n; tot=n;
	for(int i=1;i<=n;i++) s[i]=s[i+1]-s[i],a[i]=s[i];
	s[++n]=-1; a[n]=-1;
	sort(a+1,a+n+1); m=unique(a+1,a+n+1)-a-1;
	for(int i=tot;i;i--) s[++n]=s[i];
	for(int i=1;i<=n;i++) s[i]=lower_bound(a+1,a+m+1,s[i])-a;
	m=n;
	ssort(); get_h(); prework();
	solve();
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sizeof_you/article/details/85275910