题目:
给定一个字符串a,又给定一系列b字符串,求字符串a的子串不在b中出现的个数。
题解:
先将所有的查询串放入后缀自动机(每次将sam.last=1)(算出所有子串个数)
然后将母串放入后缀自动机然后记录这个子串个数
两个值相减即可

1 #include <set>
2 #include <map>
3 #include <stack>
4 #include <queue>
5 #include <cmath>
6 #include <ctime>
7 #include <cstdio>
8 #include <string>
9 #include <vector>
10 #include <cstring>
11 #include <iostream>
12 #include <algorithm>
13 #include <unordered_map>
14
15 #define pi acos(-1.0)
16 #define eps 1e-9
17 #define fi first
18 #define se second
19 #define rtl rt<<1
20 #define rtr rt<<1|1
21 #define bug printf("******\n")
22 #define mem(a, b) memset(a,b,sizeof(a))
23 #define name2str(x) #x
24 #define fuck(x) cout<<#x" = "<<x<<endl
25 #define sfi(a) scanf("%d", &a)
26 #define sffi(a, b) scanf("%d %d", &a, &b)
27 #define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c)
28 #define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
29 #define sfL(a) scanf("%lld", &a)
30 #define sffL(a, b) scanf("%lld %lld", &a, &b)
31 #define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c)
32 #define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
33 #define sfs(a) scanf("%s", a)
34 #define sffs(a, b) scanf("%s %s", a, b)
35 #define sfffs(a, b, c) scanf("%s %s %s", a, b, c)
36 #define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
37 #define FIN freopen("../in.txt","r",stdin)
38 #define gcd(a, b) __gcd(a,b)
39 #define lowbit(x) x&-x
40 #define IO iOS::sync_with_stdio(false)
41
42
43 using namespace std;
44 typedef long long LL;
45 typedef unsigned long long ULL;
46 const ULL seed = 13331;
47 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
48 const int maxm = 8e6 + 10;
49 const int INF = 0x3f3f3f3f;
50 const int mod = 1e9 + 7;
51 const int maxn = 2e5 + 7;
52
53 struct Suffix_Automaton {
54 int last, tot, nxt[maxn << 1][26], fail[maxn << 1];
55 int len[maxn << 1];// 最长子串的长度 (该节点子串数量 = len[x] - len[fa[x]])
56 int sa[maxn << 1], c[maxn << 1];
57 int sz[maxn << 1];// 被后缀链接的个数,方便求节点字符串的个数
58 LL num[maxn << 1];// 该状态子串的数量
59 LL maxx[maxn << 1];// 长度为x的子串出现次数最多的子串的数目
60 LL sum[maxn << 1];// 该节点后面所形成的自字符串的总数
61 LL subnum, sublen;// subnum表示不同字符串数目,sublen表示不同字符串总长度
62 int X[maxn << 1], Y[maxn << 1]; // Y表示排名为x的节点,X表示该长度前面还有多少个
63 void init(int n) {
64 tot = last = 1;
65 fail[1] = len[1] = 0;
66 for (int i = 0; i <= 25; i++) nxt[1][i] = 0;
67 }
68
69 void extend(int c) {
70 int u = ++tot, v = last;
71 for (int i = 0; i <= 25; i++) nxt[u][i] = 0;
72 fail[u] = 0;
73 len[u] = len[v] + 1;
74 num[u] = 1;
75 for (; v && !nxt[v][c]; v = fail[v]) nxt[v][c] = u;
76 if (!v) fail[u] = 1, sz[1]++;
77 else if (len[nxt[v][c]] == len[v] + 1) fail[u] = nxt[v][c], sz[nxt[v][c]]++;
78 else {
79 int now = ++tot, cur = nxt[v][c];
80 len[now] = len[v] + 1;
81 memcpy(nxt[now], nxt[cur], sizeof(nxt[cur]));
82 fail[now] = fail[cur];
83 fail[cur] = fail[u] = now;
84 for (; v && nxt[v][c] == cur; v = fail[v]) nxt[v][c] = now;
85 sz[now] += 2;
86 }
87 last = u;
88 }
89
90 void get_posnum() {// 每个节点子串出现的次数
91 for (int i = 1; i <= tot; i++) X[len[i]]++;
92 for (int i = 1; i <= tot; i++) X[i] += X[i - 1];
93 for (int i = 1; i <= tot; i++) Y[X[len[i]]--] = i;
94 for (int i = tot; i >= 1; i--) num[fail[Y[i]]] += num[Y[i]];
95 }
96
97 void get_maxx(int n) {// 长度为x的子串出现次数最多的子串的数目
98 get_posnum();
99 for (int i = 1; i <= tot; i++) maxx[len[i]] = max(maxx[len[i]], num[i]);
100 for (int i = n - 1; i >= 1; i--) maxx[i] = max(maxx[i], maxx[i + 1]);
101 }
102
103 void get_sum() {// 该节点后面所形成的自字符串的总数
104 get_posnum();
105 for (int i = tot; i >= 1; i--) {
106 sum[Y[i]] = 1;
107 for (int j = 0; j <= 25; j++) sum[Y[i]] += sum[nxt[Y[i]][j]];
108 }
109 }
110
111 void get_subnum() {//本质不同的子串的个数
112 subnum = 0;
113 for (int i = 1; i <= tot; i++) subnum += len[i] - len[fail[i]];
114 }
115
116 void get_sublen() {//本质不同的子串的总长度
117 sublen = 0;
118 for (int i = 1; i <= tot; i++) sublen += 1LL * (len[i] + len[fail[i]] + 1) * (len[i] - len[fail[i]]) / 2;
119 }
120
121 void get_sa() { //获取sa数组
122 for (int i = 1; i <= tot; i++) c[len[i]]++;
123 for (int i = 1; i <= tot; i++) c[i] += c[i - 1];
124 for (int i = tot; i >= 1; i--) sa[c[len[i]]--] = i;
125 }
126
127 int mx[maxn << 1];
128
129 void match(char s[]) {
130 int p = 1, maxlen = 0;
131 mem(mx, 0);
132 for (int i = 0; s[i]; i++) {
133 int c = s[i] - 'a';
134 if (nxt[p][c]) p = nxt[p][c], maxlen++;
135 else {
136 for (; p && !nxt[p][c]; p = fail[p]);
137 if (!p) p = 1, maxlen = 0;
138 else maxlen = len[p] + 1, p = nxt[p][c];
139 }
140 mx[p] = max(mx[p], maxlen);
141 }
142 }
143
144 void get_kth(int k) {
145 int pos = 1, cnt;
146 string s = "";
147 while (k) {
148 for (int i = 0; i <= 25; i++) {
149 if (nxt[pos][i] && k) {
150 cnt = nxt[pos][i];
151 if (sum[cnt] < k) k -= sum[cnt];
152 else {
153 k--;
154 pos = cnt;
155 s += (char) (i + 'a');
156 break;
157 }
158 }
159 }
160 }
161 cout << s << endl;
162 }
163
164 } sam;
165
166
167 int T, n, cas = 1;
168 char s[maxn], t[maxn];
169
170 int main() {
171 // FIN;
172 sfi(T);
173 while (T--) {
174 sfi(n);
175 sfs(s + 1);
176 int len = strlen(s + 1);
177 sam.init(len);
178 for (int i = 0; i < n; i++) {
179 sfs(t + 1);
180 len = strlen(t + 1);
181 sam.last = 1;
182 for (int j = 1; j <= len; j++) sam.extend((t[j] - 'a'));
183 }
184 sam.get_subnum();
185 LL ans1 = sam.subnum;
186 sam.last = 1;
187 len = strlen(s + 1);
188 for (int i = 1; i <= len; i++) sam.extend((s[i] - 'a'));
189 sam.get_subnum();
190 LL ans2 = sam.subnum;
191 // fuck(ans1),fuck(ans2);
192 printf("Case %d: %lld\n", cas++, ans2 - ans1);
193 }
194 return 0;
195 }
