「2019冬令營提升組」原樣輸出

傳送門ios

考慮只有一個串的如何處理函數

顯然直接後綴自動機統計不一樣的子串個數spa

考慮多個串分別構建後綴自動機code

那麼對於一個可能的合法子串,它在自動機上的匹配必定是先在第一個自動機的根節點開始一直跑,只有當前自動機沒有轉移邊了,那就跑到下一個自動機繼續轉移blog

爲了儘量地匹配因此只有當前自動機沒有轉移邊了,才跑到下一個自動機get

而後把全部子串分別構建一個後綴自動機,而後從後往前枚舉一個個連起來,(緣由代碼有註釋)string

全部自動機構成了一個$DAG$,考慮在$DAG$上 $dfs$it

若是要輸出子串,開一個棧存當前子串,每 $dfs$ 到一個節點就輸出棧內子串io

若是隻考慮統計數量則記 $f[i]$ 表示跑到節點 $i$ 之後的合法子串數量,跑記憶化搜索模板

#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring>
using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e7+7,mo=1e9+7; inline int fuck(char c)//把字符按字典序轉成序號,請不要在乎函數名...
{ if(c=='A') return 0; if(c=='C') return 1; return c=='G' ? 2 : 3; } inline char FUCK(int x)//把序號轉成字符
{ if(!x) return 'A'; if(x==1) return 'C'; return x==2 ? 'G' : 'T'; } //後綴自動機模板
int ch[N][4],fa[N],Max[N],tot,las,rt[N]; inline void ins(int c,int k) { int p=++tot,f=las; Max[las=p]=Max[f]+1; while(f&&!ch[f][c]) ch[f][c]=p,f=fa[f]; if(!f) { fa[p]=rt[k]; return; } int v=ch[f][c]; if(Max[v]==Max[f]+1) { fa[p]=v; return; } int np=++tot; Max[np]=Max[f]+1; fa[np]=fa[v]; fa[v]=fa[p]=np; memcpy(ch[np],ch[v],sizeof(ch[np])); while(f&&ch[f][c]==v) ch[f][c]=np,f=fa[f]; } int n,k,cnt,f[N]; char s[N],st[N];//st存當前棧中字符
int Top; void dfs1(int x)//暴力枚舉因此子串
{ puts(st+1); ++cnt; for(int i=0;i<4;i++) { int &v=ch[x][i]; if(!v) continue; st[++Top]=FUCK(i); dfs1(v); st[Top--]=0; } } int dfs2(int x)//記憶化dfs統計方案
{ if(f[x]) return f[x]; f[x]=1; for(int i=0;i<4;i++) { int &v=ch[x][i]; if(!v) continue; f[x]=(f[x]+dfs2(v))%mo; } return f[x]; } int main() { freopen("copy.in","r",stdin); freopen("copy.out","w",stdout); n=read(); for(int i=1;i<=n;i++) { las=rt[i]=++tot; scanf("%s",s+1); int len=strlen(s+1); for(int j=1;j<=len;j++) ins(fuck(s[j]),i); } for(int i=n;i;i--)//注意從後往前枚舉 //由於自動機i缺乏的轉移邊自動機i+1不必定有,可能在更後面的自動機有 //從後往前枚舉能夠保證 ch[rt[i+1]][k] 是後面全部自動機中第一個有 k 轉移邊的自動機
 { for(int j=rt[i];j<rt[i+1];j++) for(int k=0;k<4;k++) if(!ch[j][k]) ch[j][k]=ch[rt[i+1]][k]; } k=read(); if(k) dfs1(rt[1]),printf("%d",cnt); else dfs2(rt[1]),printf("%d",f[rt[1]]); return 0; }
相關文章
相關標籤/搜索