标签:
题意: 给一个字符串长度最大2000,给出Q个查询[l,r]包含多少种连续的子串。
解析: 后缀自动机轻松过,先对查询离线排序,对于左端点相同的建立一个后缀自动
机,字符串长度最大只有2000,所以最后只用建2000个,每个sam插入的字符最多也就
2000,时间肯定是够的。
代码
#include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; const int maxn=4005; struct SAM { int ch[maxn][26]; int pre[maxn],step[maxn]; int last,id; void init() { last=id=0; memset(ch[0],-1,sizeof(ch[0])); pre[0]=-1; step[0]=0; } void Insert(int c) //字符转化为数 { int p=last,np=++id; step[np]=step[p]+1; memset(ch[np],-1,sizeof(ch[np])); while(p!=-1&&ch[p][c]==-1) ch[p][c]=np,p=pre[p]; if(p==-1) pre[np]=0; else { int q=ch[p][c]; if(step[q]!=step[p]+1) { int nq=++id; memcpy(ch[nq],ch[q],sizeof(ch[q])); step[nq]=step[p]+1; pre[nq]=pre[q]; pre[np]=pre[q]=nq; while(p!=-1&&ch[p][c]==q) ch[p][c]=nq,p=pre[p]; } else pre[np]=q; } last=np; } int GetCnt() { int ret=0; for(int i=id;i>=1;i--) ret+=step[i]-step[pre[i]]; return ret; } }sam; char S[maxn/2]; struct Ques { int l,r,id; Ques(int l=0,int r=0,int id=0):l(l),r(r),id(id){} bool operator < (const Ques& t) const { if(l!=t.l) return l<t.l; return r<t.r; } }q[10005]; int Q,ans[10005]; void solve() { sort(q,q+Q); int last; for(int i=0;i<Q;i++) { if(i==0||q[i].l!=q[i-1].l) { sam.init(); last=q[i].l; } for(;last<=q[i].r;last++) sam.Insert(S[last]-‘a‘); ans[q[i].id]=sam.GetCnt(); } for(int i=0;i<Q;i++) printf("%d\n",ans[i]); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%s",S+1); int len=strlen(S); scanf("%d",&Q); int l,r,id; for(int i=0;i<Q;i++) { scanf("%d%d",&l,&r); q[i]=Ques(l,r,i); } solve(); } return 0; }
标签:
原文地址:http://www.cnblogs.com/wust-ouyangli/p/5808999.html