//昨天晚上一直用后缀数组来写,怎么写都超时(后来在网上看到也有用后缀数组过的,然来是自己昨晚sb,用把l,r区间的rank数组排序来使l,r区间内的rank有序,其实直接按rank,O(n)遍历就可以做到),
//今天看了多校3的官方解题,可以用后缀自动机;
//今天上午就去学习了后缀自动机(以前没有主动去学后缀自动机,总想后缀自动机能解的,后缀数组都能解,这次顺便学习一下);
//官方解题说这题后缀自动机可以O(n^2)+O(1),可是我写的后缀自动机时间复杂度还是O(n*q),因为每次计算字串的个数的还是把所有的step遍历了的一遍,
//但是没有重新建树,建树的常数小了一些;
//思考:(不知道计算字串的个数的时候可不可以利用以前的信息,也就是F数组的修改更新可不可以记录下来,去想想,继续学习后缀自动机);
//ac 代码如下:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> #include<math.h> #include<bitset> #include<string> #include<queue> #include<deque> #include<ctype.h> #include<vector> #include<set> #include<map> #include<list> #include<stack> #include<functional> #include<algorithm> using namespace std; #define N 2010 int F[N*2],ant,last,ch[N*2][26],step[N*2]; void init(){ last=ant=1; memset(F,0,sizeof(F)); memset(ch,0,sizeof(ch)); memset(step,0,sizeof(step)); } void ins(int x){ int t=++ant,pa=last; step[t]=step[last]+1;last=t; for(;pa&&!ch[pa][x];pa=F[pa]) ch[pa][x]=t; if(pa==0) F[t]=1; else if(step[pa]+1==step[ch[pa][x]]) F[t]=ch[pa][x]; else { int nq=++ant,q=ch[pa][x]; memcpy(ch[nq],ch[q],sizeof(ch[nq])); step[nq]=step[pa]+1;F[nq]=F[q];F[q]=F[t]=nq; for(;pa&&ch[pa][x]==q;pa=F[pa]) ch[pa][x]=nq; } } //以上为后缀自动机的部分 char s[N]; int ans[10100]; vector<pair<int,int> > Q[N]; void run(int p){ int i,t,j,tt; init(); sort(Q[p].begin(),Q[p].end()); for(i=0,t=p-1;i<(int)Q[p].size();i++){ if(i&&Q[p][i].first==t){ ans[Q[p][i].second]=tt; continue; } while(t<Q[p][i].first){ ins(s[t]-'a');t++; } for(tt=0,j=ant;j>0;j--) tt+=step[j]-step[F[j]]; ans[Q[p][i].second]=tt; } } int main(){ int cas,n,i,a,b,m; scanf("%d",&cas); while(cas--){ scanf("%s",s);m=strlen(s); for(i=1;i<=m;i++) Q[i].clear(); scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d%d",&a,&b); Q[a].push_back(make_pair(b,i)); } for(i=1;i<=m;i++) if(Q[i].size()) run(i); for(i=1;i<=n;i++) printf("%d\n",ans[i]); } return 0; }
//后缀数组修改后ac的代码
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> using namespace std; const int maxn = 2100; char s[maxn]; int sa[maxn],t[maxn],t2[maxn],c[maxn]; void build_sa(int n,int m){ int i,k,*x=t,*y=t2,p; //基数排序 for(i=0;i<m;i++) c[i]=0; for(i=0;i<n;i++) c[x[i]=s[i]]++; for(i=1;i<m;i++) c[i]+=c[i-1]; for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(k=1;k<n;k*=2){ p=0; //直接利用sa数组排序第二关键字 for(i=n-k;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; //基数排序第一关键字 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]; //根据sa和y数组计算新的x数组 swap(x,y); p=1; x[sa[0]]=0; for(i=1;i<n;i++) 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; } } int rank[maxn],height[maxn]; void getHeight(int n) { int i,j,k=0; for(i=1;i<=n;i++) rank[sa[i]] = i; for(i=0;i<n;i++){ if(rank[i]==1)continue; if(k)k--; j=sa[rank[i]-1]; while(s[i+k]==s[j+k])k++; height[rank[i]]=k; } } int dp[maxn][maxn]; void brute_rmp(int n){ int i,k,ans; for(k=1;k<=n;k++){ ans=n+n; for(i=k+1;i<=n;i++){ ans=min(ans,height[i]); dp[k][i]=ans; } } } struct node{ int k,d; }A[maxn]; int M; int run(int l,int r) { int n=r-l+1,i,ans=0,k; for(i=k=1;i<=M;i++){ //昨天就是sb在这儿(对A[i].k排序),不知道写这个循环来得到一个rank有序的A[] if(l<=sa[i]&&sa[i]<=r){ A[k].k=i;A[k].d=r-sa[i]+1;k++; }if(k>n) break; } ans+=A[1].d; int b=1; for(i=2;i<=n;i++){ ans+=A[i].d-min(A[i].d,min(A[b].d,dp[A[b].k][A[i].k])); if(A[b].d>A[i].d&&dp[A[b].k][A[i].k]>=A[i].d); else b=i; } return ans; } int main(){ int cas,n,a,b; scanf("%d",&cas); while(cas--){ scanf("%s",s); M=strlen(s); build_sa(M+1,255); getHeight(M);brute_rmp(M); scanf("%d",&n); while(n--){ scanf("%d%d",&a,&b); printf("%d\n",run(a-1,b-1)); } } return 0; }