SPOJ DISUBSTR 后缀数组

来源:互联网 发布:知乎 陈廖宇 编辑:程序博客网 时间:2024/06/12 18:31

题意

有T个字符串,问每个字符串有多少不同的子串。

题解

后缀数组模板题,基本上模板套上去就能AC。当然了,还是有点变化的。关于后缀数组的题,首先观察Height特征。
后缀数组
可以发现,字符子串数量之和即为后缀长度之和。不过,子串有重复的,需要去重。观察height数组就会发现,height数组记录的就是两个后缀之间重复的前缀数量。因此后缀长度-height求和就可以了。

注意事项

第一次写后缀数组,忘记加尾字符$了,所以一直过不了样例,ORZ。。

代码

#include <iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<string>#include<set>#include<map>#include<bitset>#include<stack>#include<string>#pragma comment(linker,"/STACK:102400000,102400000")#define UP(i,l,h) for(int i=l;i<h;i++)#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)#define W(a) while(a)#define MEM(a,b) memset(a,b,sizeof(a))#define LL long long#define INF 0x3f3f3f3f#define MAXN 50010#define MOD 1000000007#define EPS 1e-3using namespace std;struct Node {    int to,val;    Node(int to,int val):to(to),val(val) {}};char s[MAXN];int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n,rk[MAXN],height[MAXN];void build_sa(int m) {    int i,*x=t,*y=t2;    UP(i,0,m) c[i]=0;    UP(i,0,n) c[x[i]=s[i]]++;    UP(i,1,m) c[i]+=c[i-1];    DOWN(i,n,0) sa[--c[x[i]]]=i;    for(int k=1; k<=n; k<<=1) {        int p=0;        UP(i,n-k,n) y[p++]=i;        UP(i,0,n) if(sa[i]>=k) y[p++]=sa[i]-k;        UP(i,0,m) c[i]=0;        UP(i,0,n) c[x[y[i]]]++;        UP(i,0,m) c[i]+=c[i-1];        DOWN(i,n,0) sa[--c[x[y[i]]]]=y[i];        swap(x,y);        p=1;        x[sa[0]]=0;        UP(i,1,n)            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;        if(p>=n) break;        m=p;    }}void getHeight(){    int i,j,k=0;    UP(i,0,n) rk[sa[i]]=i;    UP(i,0,n-1){        if(k)            k--;        int j=sa[rk[i]-1];        W(s[i+k]==s[j+k])            k++;        height[rk[i]]=k;    }}int main() {    int t;    scanf("%d",&t);    W(t--) {        scanf("%s",s);        n=strlen(s);        build_sa(128);        getHeight();        int ans=0;        UP(i,1,n) {            ans+=(n-1-sa[i]-height[i]);        }        printf("%d\n",ans);    }}
原创粉丝点击