3277: 串

3277: 串

https://www.lydsy.com/JudgeOnline/problem.php?id=3277

分析:

广义后缀自动机是什么?

广义后缀自动机不就是把很多串的SAM建到了一个SAM上,建每个串的时候都从root开始(last=root)就行了。

广义后缀自动机是Trie树的后缀自动机,可以解决多主串问题。

                              ——candy?

首先一个结论:在后缀自动机上:每个状态表示的串的个数为len[i] - len[fa[i]。

这道题我们可以预处理出后缀自动机上每个节点所表示的串 是 哪些主串的子串,记录cnt[i]。如果cnt[i]>=k那么这个节点表示的所有串,会给包含它的主串增加贡献,贡献为Len[i]-len[fa[i]]。

然后枚举每个串的一个前缀,这时只要求出这个前缀有多少个后缀满足>=k就好了。

枚举的每个前缀,它都可以在自动机上走一个点,如果这个点满足>=k,那当前点的所有后缀都可以为它提供贡献,那么就是parent树上其所有祖先和它的和。所以要预先dfs一下每个点的值。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 inline int read() {
 6     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 7     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 8 }
 9 
10 const int N = 200100;
11 
12 struct SuffixAutomaton{
13     int Last, Index, fa[N], trans[N][26], len[N];
14     int n, k, cnt[N], cur[N];
15     bool vis[N];
16     string s[N];
17     char ss[N];
18     
19     void extend(int c) {
20         int P = Last, NP = ++Index;
21         len[NP] = len[P] + 1;
22         for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP;
23         if (!P) fa[NP] = 1;
24         else {
25             int Q = trans[P][c];
26             if (len[P] + 1 == len[Q]) fa[NP] = Q;
27             else {
28                 int NQ = ++Index;
29                 fa[NQ] = fa[Q];
30                 len[NQ] = len[P] + 1;
31                 memcpy(trans[NQ], trans[Q], sizeof trans[Q]);
32                 fa[Q] = NQ;
33                 fa[NP] = NQ;
34                 for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ;
35             }
36         }
37         Last = NP;
38     }
39     void build() {
40         Index = 1;
41         for (int i=1; i<=n; ++i) { // 广义后缀自动机的构建 
42             Last = 1;
43             scanf("%s",ss);
44             s[i] = string(ss);
45             for (int j=0,L=s[i].length(); j<L; ++j) 
46                 extend(s[i][j] - 'a');
47         }
48     }
49     void dfs(int u) {
50         if (u == 1 || vis[u]) return ;
51         vis[u] = true;
52         dfs(fa[u]);
53         cnt[u] += cnt[fa[u]];
54     }
55     void solve() {
56         n = read(),k = read();
57         build();        
58         for (int i=1; i<=n; ++i) {
59             int u = 1;
60             for (int j=0,L=s[i].length(); j<L; ++j) {
61                 u = trans[u][s[i][j]-'a']; // 第i个串的一个前缀 
62                 for (int p=u; p&&cur[p]!=i; p=fa[p]) 
63                     cur[p] = i, cnt[p] ++;// cnt 当前状态是几个串的子串 
64             }
65         }
66         for (int i=1; i<=Index; ++i) cnt[i] = (cnt[i] >= k) * (len[i] - len[fa[i]]);
67         memset(vis, false, sizeof(vis));
68         for (int i=1; i<=Index; ++i) if (!vis[i]) dfs(i);
69         for (int i=1; i<=n; ++i) {
70             int ans = 0, u = 1;
71             for (int j=0,L=s[i].length(); j<L; ++j) 
72                 u = trans[u][s[i][j]-'a'], ans += cnt[u];
73             printf("%d ",ans);
74         }
75     }
76 }sam;
77 
78 int main() {
79     sam.solve();
80     return 0;
81 }

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/9342725.html
今日推荐