height[i] 表示 排第i的子串和第i-1的子串的最长公共前缀,对于某一个长度k,如果存在连续一段height值大于等于k且起始位置的最远距离大于等于k,这一段就存在一个解,ans加1
#include<stdio.h> #include<string> #include<map> #include<vector> #include<cmath> #include<stdlib.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; #define rep(i,n) for(int i=0;i<n;i++) #define repp(i,j,k) for(int i=j;i<k;i++) const int N=2e3+10; const int MOD=1e9+7; const int inf=1e9; int n,m,k,up,p; char s[N]; int f[N],sa[N],cnt[N],sr[N],r[N],height[N]; int len; void getSa(){ int up=0; rep(i,len) up=max(up,(int)s[i]); up++; rep(i,up) cnt[i]=0; rep(i,len) cnt[f[i]=s[i]]++; repp(i,1,up) cnt[i]+=cnt[i-1]; for(int i=len-1;i>=0;i--) sa[--cnt[f[i]]]=i; int d=1,p=0; while(d<len){ repp(i,len-d,len) sr[p++]=i; rep(i,len) if(sa[i]>=d) sr[p++]=sa[i]-d; rep(i,up) cnt[i]=0; rep(i,len) cnt[f[sr[i]]]++; repp(i,1,up) cnt[i]+=cnt[i-1]; for(int i=len-1;i>=0;i--) sa[--cnt[f[sr[i]]]]=sr[i]; swap(f,r); p=0; f[sa[0]]=p++; rep(i,len-1) f[sa[i+1]]=(sa[i]+d<len && sa[i+1]+d<len && r[sa[i]+d]==r[sa[i+1]+d] && r[sa[i]]==r[sa[i+1]])?p-1:p++; d*=2;up=p;p=0; } rep(i,len) f[sa[i]]=i; } void getH(){ int p=0; rep(i,len){ if(f[i]==0) {height[f[i]]=0;continue;} int k=sa[f[i]-1]; while(i+p<len && k+p<len && s[i+p]==s[k+p]) p++; height[f[i]]=p; p=max(0,p-1); } } int solve(int x){ int l=1e9,r=0; int ans=0; repp(i,1,len){ if(height[i]<x){ if(r-l>=x) ans++; l=1e9;r=0; }else{ l=min(l,min(sa[i],sa[i-1])); r=max(r,max(sa[i],sa[i-1])); } } if(r-l>=x) ans++; return ans; } int main(){ #ifndef ONLINE_JUDGE freopen("aaa","r",stdin); #endif int T; while(~scanf("%s",s),s[0]!='#'){ len=strlen(s); getSa(); getH(); long long ans=0; for(int i=1;i<=len/2;i++) ans+=solve(i); printf("%I64d\n",ans); } return 0; }