题意
描述:
给出(n)个字符串,你可能会回答两种询问中的一个:
(k=0):其中每个串的连续子串拼接起来共有多少个不同的串;
(k=1):回答(k=0),并且输出所有的子串;
范围:
保证输入不超过(1 M) ,输出不超过(200 M)
题解:
-
对每个串建后缀自动机;
-
把每个后缀自动机的空节点仿照子序列自动机那样补上;
-
(dp)统计答案,(dfs)输出方案;
-
复杂度是(O(4*n))的;
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1<<21,mod=1e9+7; int n,k,nxt[4],l[N]; int cnt,rt[N],len[N],pa[N],ch[N][4],lst,now,L[N],d[N]; int st[N],top,c[N],f[N],ans; queue<int>q; char s[N],mp[4]={'A','C','G','T'}; int get(char x){return x=='A'?0:x=='C'?1:x=='G'?2:3;} void extend(int x){ int p=lst,np=++cnt;lst=np; len[np]=len[p]+1; while(p&&!ch[p][x])ch[p][x]=np,p=pa[p]; if(!ch[p][x]){pa[np]=now;return;} int q=ch[p][x]; if(len[q]==len[p]+1){pa[np]=q;return;} int nq=++cnt; len[nq]=len[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); pa[nq]=pa[q];pa[q]=pa[np]=nq; while(p&&ch[p][x]==q)ch[p][x]=nq,p=pa[p]; } void dfs(int u){ for(int i=1;i<=top;++i)putchar(mp[st[i]]); putchar(' ');ans++; for(int i=0;i<4;++i)if(ch[u][i]){ st[++top]=i; dfs(ch[u][i]); --top; } } int main(){ freopen("copy.in","r",stdin); freopen("copy.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%s",s+1); l[i]=strlen(s+1); rt[i]=now=lst=++cnt; for(int j=1;j<=l[i];++j)extend(get(s[j])); } scanf("%d",&k); for(int i=n;i;--i){ now=rt[i]; for(int j=now;j<rt[i+1];++j) for(int k=0;k<4;++k)if(!ch[j][k])ch[j][k]=nxt[k]; for(int j=0;j<4;++j)if(ch[now][j])nxt[j]=ch[now][j]; } if(k==1)dfs(1); else { for(int i=1;i<=cnt;++i) for(int j=0;j<4;++j)d[ch[i][j]]++; for(int i=1;i<=cnt;++i)if(!d[i])q.push(i),st[++top]=i; while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<4;++i)if(!--d[ch[x][i]])q.push(ch[x][i]),st[++top]=ch[x][i]; } for(int i=cnt,x;i;--i){ f[x=st[i]]++; for(int j=0;j<4;++j)if(ch[x][j]){f[x]+=f[ch[x][j]];if(f[x]>=mod)f[x]-=mod;} } ans=f[1]; } printf("%d ",ans%mod); return 0; }