题意
给出n个字符串,每个字符串的开头和结尾可以去除一些连续的子串,也可以不删。问这样删去后连成的不同字符串有多少个。要求线性。
思考
如果是一个字符串,那么建一颗SAM即可。
因为是几个字符串拼在一起,那么在某个字符串的SAM上的某一个点,随时都可以跳到下一个字符串的SAM上的某个一点。那么从后往前建SAM,第i颗SAM往第i+1颗SAM连边。
统计用了拓扑。
代码
1 // luogu-judger-enable-o2 2 // luogu-judger-enable-o2 3 #define mod 1000000007 4 #include<bits/stdc++.h> 5 using namespace std; 6 const int maxn=2E6+5; 7 typedef long long int ll; 8 int n,k,tot,root; 9 int size,wait[maxn]; 10 int GG[maxn*2]; 11 int in[maxn*2]; 12 int f[maxn*2]; 13 bool vis[maxn*2]; 14 string str[maxn]; 15 string ans; 16 inline int to(char ch) 17 { 18 if(ch=='A') 19 return 0; 20 else if(ch=='C') 21 return 1; 22 else if(ch=='G') 23 return 2; 24 return 3; 25 } 26 inline char back(int x) 27 { 28 if(x==0) 29 return 'A'; 30 else if(x==1) 31 return 'C'; 32 else if(x==2) 33 return 'G'; 34 return 'T'; 35 } 36 struct node 37 { 38 int len,fa,ch[4]; 39 }; 40 struct SAM 41 { 42 node t[maxn*2]; 43 int last; 44 inline void insert(int x) 45 { 46 int now=++tot,u=last; 47 last=tot; 48 t[now].len=t[u].len+1; 49 for(;u&&!t[u].ch[x];u=t[u].fa) 50 t[u].ch[x]=now; 51 if(!u) 52 t[now].fa=root; 53 else 54 { 55 int v=t[u].ch[x]; 56 if(t[v].len==t[u].len+1) 57 t[now].fa=v; 58 else 59 { 60 int w=++tot; 61 t[w]=t[v]; 62 t[w].len=t[u].len+1; 63 t[v].fa=t[now].fa=w; 64 for(;u&&t[u].ch[x]==v;u=t[u].fa) 65 t[u].ch[x]=w; 66 } 67 } 68 } 69 inline ll calc() 70 { 71 memset(vis,0,sizeof(vis)); 72 for(int i=1;i<=tot;++i) 73 for(int j=0;j<4;++j) 74 { 75 if(!t[i].ch[j]) 76 continue; 77 ++in[t[i].ch[j]]; 78 vis[t[i].ch[j]]=1; 79 } 80 queue<int>Q; 81 for(int i=1;i<=tot;++i) 82 if(!vis[i]) 83 Q.push(i); 84 int cnt=0; 85 while(!Q.empty()) 86 { 87 int u=Q.front(); 88 Q.pop(); 89 GG[++cnt]=u; 90 for(int i=0;i<4;++i) 91 { 92 int v=t[u].ch[i]; 93 if(!v) 94 continue; 95 --in[v]; 96 if(!in[v]) 97 Q.push(v); 98 } 99 } 100 ll sum=0; 101 for(int i=cnt;i>=1;--i) 102 { 103 int u=GG[i]; 104 f[u]=1; 105 for(int j=0;j<4;++j) 106 { 107 int v=t[u].ch[j]; 108 if(!v) 109 continue; 110 f[u]=(f[u]+f[v])%mod; 111 } 112 } 113 return f[root]; 114 } 115 void out(int u) 116 { 117 cout<<ans<<endl; 118 for(int i=0;i<4;++i) 119 if(t[u].ch[i]) 120 { 121 ans+=back(i); 122 out(t[u].ch[i]); 123 ans.pop_back(); 124 } 125 } 126 void com(int u) 127 { 128 if(!vis[u]) 129 wait[++size]=u; 130 else 131 return; 132 vis[u]=1; 133 for(int i=0;i<4;++i) 134 if(t[u].ch[i]) 135 com(t[u].ch[i]); 136 } 137 138 }S; 139 int main() 140 { 141 ios::sync_with_stdio(false); 142 cin>>n; 143 for(int i=1;i<=n;++i) 144 cin>>str[i]; 145 int last=0,now=0; 146 for(int G=n;G>=1;--G) 147 { 148 root=S.last=now=++tot; 149 for(int i=0;i<str[G].size();++i) 150 S.insert(to(str[G][i])); 151 if(G!=n) 152 { 153 size=0; 154 S.com(now); 155 for(int i=1;i<=size;++i) 156 { 157 int u=wait[i]; 158 for(int j=0;j<4;++j) 159 if(!S.t[u].ch[j]&&S.t[last].ch[j]) 160 S.t[u].ch[j]=S.t[last].ch[j]; 161 } 162 } 163 last=now; 164 } 165 cin>>k; 166 if(k==0) 167 cout<<S.calc()<<endl; 168 else 169 { 170 S.out(now); 171 cout<<S.calc()<<endl; 172 } 173 return 0; 174 }