标签:lin 建立 math 题意 main pen turn 字典序 超过
给你 \(n\) 个字符串,选每个字符串的一个子串依次拼在一起形成一个字符串 \(T\) 。按字典序输出所有可能的 \(T\) 并统计方案数。
(输入文件不超过 1 MB ,输出文件不超过 200 MB .)
对每个字符串都建立一个 SAM 。如果某个节点没有转移边,则连向右边 SAM (最靠左的)根的转移边指向的节点。
输出直接 dfs ,统计方案数直接拓扑序。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
const int N=3000005,M=7000005,Mod=1000000007;
int pre[N],len[N],ch[N][5],lst,cnt,rt[N],size[N];
int n,m[233],get[N],head[N],nxt[M],to[M],tot,in[N],pl[N],q[N];
char ans[N],h[5];
string s[N];
void extend(int r, int c)
{
int p=lst,np=++cnt;lst=np;
len[np]=len[p]+1,size[np]=1;
for(;p&&!ch[p][c];p=pre[p]) ch[p][c]=np;
if(!p) {
pre[np]=r;
return ;
}
int q=ch[p][c];
if(len[p]+1==len[q]) {
pre[np]=q;
return ;
}
int nq=++cnt;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
pre[nq]=pre[q],pre[q]=pre[np]=nq;
for(;ch[p][c]==q;p=pre[p])ch[p][c]=nq;
}
void addedge(int u, int v) {
++in[v],nxt[++tot]=head[u];head[u]=tot,to[tot]=v;
}
void dfs(int u, int v)
{
puts(ans);
for(int i=1;i<=4;++i)
if(ch[u][i])
{
ans[v]=h[i];
dfs(ch[u][i],v+1);
ans[v]='\0';
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("3446.in","r",stdin);
freopen("3446.out","w",stdout);
#endif
cin>>n;
m['A']=1,m['C']=2,m['G']=3,m['T']=4;
h[1]='A',h[2]='C',h[3]='G',h[4]='T';
for(int i=1;i<=n;++i) cin>>s[i];
for(int i=n;i>=1;--i)
{
lst=rt[i]=++cnt;
for(int j=0;j<s[i].size();++j) extend(rt[i],m[s[i][j]]);
for(int j=rt[i];j<=cnt;++j)
{
for(int k=1;k<=4;++k)
{
if(!ch[j][k]) ch[j][k]=get[k];
if(ch[j][k]) addedge(ch[j][k],j);
}
}
for(int k=1;k<=4;++k)
if(ch[rt[i]][k]) get[k]=ch[rt[i]][k];
}
int k; cin>>k;
if(k) dfs(rt[1],0);
int l=1,r=0;
for(int i=1;i<=cnt;++i)
{
pl[i]=1;
if(!in[i]) q[++r]=i;
}
while(l<=r)
{
int u=q[l++];
for(int e=head[u];e;e=nxt[e])
{
pl[to[e]]=(pl[to[e]]+pl[u])%Mod;
--in[to[e]];
if(!in[to[e]]) q[++r]=to[e];
}
}
cout<<pl[rt[1]];
}
标签:lin 建立 math 题意 main pen turn 字典序 超过
原文地址:https://www.cnblogs.com/farway17/p/10447669.html