题意很简单,给一个字符串,求这个字符串有多少个不同的子串。这两题其实是一道,只不过694的范围是1000,705的范围是50000。写后缀数组的话,先求出sa,height这两个数组,因为每个后缀一定是一个独一无二的子串,所以可以直接把len先给ans,接下来就是找非后缀的子串,我的做法是直接循环sa,因为相邻的后缀已经是最相近的了,我要添加的就只是后缀i中从height[i]+1位开始到倒数第二位这些子串(height[i]位的情况上一层已经添加过,到最后一位的情况算到之前的len种情况里了)。循环完直接输出答案即可。代码见下。
#include <iostream> #include <algorithm> #include <cmath> #include <cstdio> #include <algorithm> #include <stack> #include <queue> #include <map> #include <string> #include <cstring> #include <string> using namespace std; typedef long long ll; const int maxn=80000+40; int s[maxn],rs[maxn]; int sa[maxn],t[maxn],t2[maxn],c[maxn]; int n,m,k; char s1[maxn],s2[maxn]; int rank[maxn],height[maxn]; int l1,l2; void getheight(int n) { int i,j,k=0; for (i=0; i<=n; i++) rank[sa[i]]=i; for (i=0; i<n; i++) { if (k) k--; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k]) k++; height[rank[i]]=k; } } void build_ss(int m,int n) { n++; int i,*x=t,*y=t2; for (int i=0; i<m; i++) c[i]=0; for (int i=0; i<n; i++) c[x[i]=s[i]]++; for (int i=1; i<m; i++) c[i]+=c[i-1]; for (int i=n-1; i>=0; i--) sa[--c[x[i]]]=i; for (int k=1; k<=n; k<<=1) { int p=0; 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]; 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 tt,ans; int main() { // freopen("in.txt","r",stdin); scanf("%d",&tt); while(tt--) { scanf("%s",s1); int l=strlen(s1); n=l; m=0; for (int i=0; i<l; i++) { s[i]=s1[i]; m=max(m,s[i]); } s[l]=0; build_ss(m+1,n); getheight(n); ans=n; int tp; for (int i=1; i<=n; i++) { tp=n-sa[i]; ans+=(tp-1-height[i]); } printf("%d\n",ans); } return 0; }
另外,我感觉这题后缀自动机应该也能写,我写的时候是先建好了后缀自动机,从每一个节点开始,走到任何一个节点都是一个独一无二的子串,所以只要统计一下就行,1000的毫无压力的过掉了,但50000的TLE到死..DFS统计TLE,换成从起点一层一层的递推还是TLE..后来想了想这么统计复杂度严格来说应该是O(边数)而不是O(n),可能是这T掉了吧。有大神看到了还求指导这题后缀自动机的做法。代码还是贴一下吧。
//只能过694。705TLE #include <vector> #include <iostream> #include <cstdio> #include <algorithm> #include <memory.h> #include <cmath> #include <queue> #include <stack> #include <map> #include <string> #include <cstring> using namespace std; typedef long long ll; typedef vector<int> vi; const int maxn=100100; const int S=256; int tot,len; int n,m; int wtop[maxn]; int c[maxn]; int k; int ans; struct node { node *par,*go[S]; int val,sk; int id; }*tail,*root,que[maxn],*top[maxn]; char str[maxn],s[maxn],ss[maxn]; inline int idx(char s) { // if (s>='A' && s<='Z') return s-'A'; // if (s>='a' && s<='z') return s-'a'+26; // return 52+s-'0'; return (int)s; } inline void init(int m) { for (int i=0; i<=m; i++) { memset(que[i].go,0,sizeof que[i].go); que[i].id=que[i].val=que[i].sk=0; } tot=0; len=1; root=tail=&que[tot++]; root->id=0; ans=0; } void add(int c,int l) { node* p=tail; node* np=&que[tot++]; np->val=l; np->id=tot-1; while(p && p->go[c]==NULL) p->go[c]=np,p=p->par; if (p==NULL) np->par=root; else { node *q=p->go[c]; if (p->val+1==q->val) np->par=q; else { node *nq=&que[tot++]; *nq=*q; nq->id=tot-1; nq->val=p->val+1; np->par=q->par=nq; while(p && p->go[c]==q) p->go[c]=nq,p=p->par; } } tail=np; } void debug_suff() { for (int i=0; i<tot; i++) { for (int c=0; c<S; c++) if (que[i].go[c]) { cout<<que[i].id<<" "<<que[i].go[c]->id<<endl; } } } void debug_pre() { for (int i=1; i<tot; i++) { cout<<que[i].id<<" "<<que[i].par->id<<endl; } } inline void TopS() { memset(c,0,sizeof c); for (int i=0; i<tot; i++) c[que[i].val]++; for (int i=1; i<len; i++) c[i]+=c[i-1]; for (int i=0; i<tot; i++) top[--c[que[i].val]]=&que[i],wtop[c[que[i].val]]=i; } int tt; int main() { // freopen("in.txt","r",stdin); scanf("%d",&tt); while(tt--) { scanf("%s",s); int l=strlen(s); init(l<<1); for (int i=0; i<l; i++) { add(idx(s[i]),len++); } // debug_suff(); // puts(" "); // debug_pre(); node *rt=root; rt->sk=1; TopS(); for (int i=0; i<tot; i++) { rt=top[i]; ans+=rt->sk; for(int c=0; c<S; c++) { if (rt->go[c]) { rt->go[c]->sk+=rt->sk; } } } printf("%d\n",ans-1); } return 0; }