hdu4622([u,v]内有多少个子串)
题:http://acm.hdu.edu.cn/showproblem.php?pid=4622
题意:求[u,v]区间内有多少不同的子串,N<=2000,q<=10000
分析:建立i....n个字符串的SAM,就可以预处理各个区间字符串的数目。
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; typedef long long ll; const int M=2e3+3; int trans[M<<1][26],slink[M<<1],maxlen[M<<1]; int endpos[M<<1]; int last,now,root; void init(){ now=last=root=1; memset(trans,0,sizeof(trans)); memset(slink,0,sizeof(slink)); memset(maxlen,0,sizeof(maxlen)); } void extend(int c){ maxlen[++now]=maxlen[last]+1; int p=last,np=now; while(p&&!trans[p][c]){ trans[p][c]=np; p=slink[p]; } if(!p) slink[np]=root; else{ int q=trans[p][c]; if(maxlen[p]+1!=maxlen[q]){ maxlen[++now]=maxlen[p]+1; int nq=now; memcpy(trans[nq],trans[q],sizeof(trans[q])); slink[nq]=slink[q]; slink[q]=slink[np]=nq; while(p&&trans[p][c]==q){ trans[p][c]=nq; p=slink[p]; } } else slink[np]=q; } last=np; endpos[np]=1; } char s[M]; ll ans[M][M]; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s",s); int n=strlen(s); for(int i=0;i<n;i++){ init(); ll sum=0; for(int j=i;j<n;j++){ extend(s[j]-'a'); sum+=maxlen[last]-maxlen[slink[last]]; ans[i+1][j+1]=sum; } } int q; scanf("%d",&q); while(q--){ int u,v; scanf("%d%d",&u,&v); printf("%lld\n",ans[u][v]); } } return 0; }