HDU 3518 Boring counting(后缀数组)
程序员文章站
2022-05-11 23:17:35
...
题意:
求出不重叠切出现次数超过两次的子串个数
题解:
后缀数组分组后,判断每组出现的sa最大值和最小值之差是否是大于k就好了,k通过枚举即可
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 2000+50;
char s[MAXN];
int rk[MAXN],h[MAXN],y[MAXN],sa[MAXN],c[MAXN];
inline void SA(int n,int m){
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[rk[i]=s[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[rk[i]]]=i;
for(int k=1;k<=n;k<<=1){
int num=0;
for(int i=n-k;i<n;i++) y[num++]=i;
for(int i=0;i<n;i++) if(sa[i]>=k) y[num++]=sa[i]-k;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[rk[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[rk[y[i]]]]=y[i];
swap(rk,y);
rk[sa[0]]=0,num=1;
for(int i=1;i<n;i++)
rk[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? num-1:num++);
if(num>=n) break;
m=num;
}
}
inline void H(int n){
for(int i=1;i<=n;i++) rk[sa[i]]=i;
for(int i=0,k=0;i<n;i++){
if(k) k--; else k=0;
int j=sa[rk[i]-1];
while(s[j+k]==s[i+k]) k++;
h[rk[i]]=k;
}
}
inline int solve(int k,int n){
int ma=0,mi=INF,cnt=0;
for(int i=1;i<=n;i++){
if(h[i]<k){
if(ma-mi>=k) cnt++;
ma=0,mi=INF;
}else{
ma=max(ma,max(sa[i],sa[i-1]));
mi=min(mi,min(sa[i],sa[i-1]));
}
}
if(ma-mi>=k) cnt++;
return cnt;
}
int main(){
while(~scanf("%s",s) && s[0]!='#'){
int n=strlen(s);
SA(n+1,'z'+1);
H(n);
int ans=0;
for(int i=1;i<=n/2;i++) ans += solve(i,n);
printf("%d\n",ans);
}
return 0;
}
上一篇: 在GridView中设置item响应事件并获取其中一个控件的信息
下一篇: poj2774