[校内训练19_09_02]原样输出

题意

给出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 }
View Code
原文地址:https://www.cnblogs.com/GreenDuck/p/11553620.html