spoj
题目大意:给一个字符串s,输出其不同子串的个数。|s|<=50000
思路分析:直接暴力枚举子串去重 n^3直接爆。后缀数组可求height数组,然后第sa[i]个后缀包含的不同子串为n-height[i]-sa [i],遍历一遍叠加即可,求后缀数组为nlog(n).
代码:
#include<iostream>
#include<string.h>
#include<math.h>
#include<stdio.h>
using namespace std;
char s[100010];
int sa[100010],c[100010],x[100010],y[100010],r[100010],h[100010];
void build(int n,int m){
int i,j,k;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++){
x[i]=s[i];
c[x[i]]++;
}
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=0;i<n;i++) sa[--c[x[i]]]=i;
for(j=1;j<n;j*=2){
k=0;
for(i=n-j;i<n;i++) y[k++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[k++]=sa[i]-j;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
m=1;
x[sa[0]]=0;
for(i=1;i<n;i++){
if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=m-1;
else x[sa[i]]=m++;
}
if(m>=n) break;
}
}
void height(int n){
int i,j,k=0;
for(i=0;i<=n;i++) r[sa[i]]=i;
for(i=0;i<n;i++){
if(k) k--;
j=sa[r[i]-1];
while(s[i+k]==s[j+k]) k++;
h[r[i]]=k;
}
}
int main(){
int i,t,n;
scanf("%d",&t);
while(t--){
scanf("%s",&s);
n=strlen(s);
s[n]=0;
build(n+1,2000);
height(n);
long long sum=0;
for(i=1;i<=n;i++){
sum+=n-h[i]-sa[i];
}
cout<<sum<<endl;
}
return 0;
}
hdoj 5769
题目大意:给字符串s,字符x,求包含字符x的不同子串的个数。|s|<=100000
思路分析:大致思路同上,只是求不同子串时要考虑第一个出现在s[i]后x的位置,先处理x的位置再二分一下。。。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
char s[100010],t[10];
int sa[100010],c[100010],x[100010],y[100010],r[100010],h[100010];
void build(int n){
int i,j,k,p,m=30;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++){
x[i]=s[i]-'a'+1;
c[x[i]]++;
}
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=0;i<n;i++) sa[--c[x[i]]]=i;
for(j=1;j<n;j*=2){
p=0;
for(i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
m=0;
x[sa[0]]=m++;
for(i=1;i<n;i++){
if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=m-1;
else x[sa[i]]=m++;
}
if(m>=n) break;
}
}
void height(int n){
int i,j,k=0;
for(i=1;i<=n;i++) r[sa[i]]=i;
for(i=0;i<n;i++){
if(k) k--;
j=sa[r[i]-1];
while(s[i+k]==s[j+k]) k++;
h[r[i]]=k;
}
}
int A[100010];
int main(){
int T,i,n,k,j=0;
scanf("%d",&T);
while(T--){
j++;
scanf("%s",&t);
scanf("%s",&s);
n=strlen(s);
s[n]='a'-1;
build(n+1);
height(n);
//for(i=1;i<=n;i++) cout<<h[i]<<endl;
k=0;
for(i=0;i<n;i++) if(s[i]==t[0]) A[k++]=i;
long long a,sum=0;
for(i=1;i<=n;i++){
a=lower_bound(A,A+k,sa[i])-A;
if(a==k) continue; //木有找到sa[i]后的x
a=A[a];
if(a<=sa[i]+h[i]-1) a=sa[i]+h[i]; //x出现在公共前缀部分
sum+=n-a;
}
cout<<"Case #"<<j<<": "<<sum<<endl;
}
return 0;
}