[hdu4416 Good Article Good sentence]后缀自动机SAM
题意:给出串A和串集合B={B1,B2,...,Bn},求串A的所有不同子串中不是B中任一串的子串的数目。
思路:把A和B中所有字符串依次拼接在一起,然后构造后缀自动机,计算每个状态的R集合元素的最大值r,然后统计那些r≤length(A)的状态。hdu不卡时间卡空间,这是最郁闷的。。。导致下面的程序只在本地随机数据没发现错误,提交就MLE。
#include <bits/stdc++.h> using namespace std; #define X first #define Y second #define pb(x) push_back(x) #define mp(x, y) make_pair(x, y) #define all(a) (a).begin(), (a).end() #define mset(a, x) memset(a, x, sizeof(a)) #define mcpy(a, b) memcpy(a, b, sizeof(b)) #define cas() int T, cas = 0; cin >> T; while (T --) template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;} template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;} typedef long long ll; typedef pair<int, int> pii; #ifndef ONLINE_JUDGE #include "local.h" #endif const int N = 6e5 + 7; int len; //注意空间为 DOUBLE SIZE class SAM { public: void init() { memset(node, 0, sizeof(node)); sz = last = 0; node[0].len = 0; node[0].link = -1; sz ++; } void add(char c) { int cur = sz ++; node[cur].len = node[last].len + 1; node[cur].r = node[cur].len; int p; for (p = last; ~p && !node[p].next[c]; p = node[p].link) { node[p].next[c] = cur; } if (p == -1) node[cur].link = 0; else { int q = node[p].next[c]; if (node[p].len + 1 == node[q].len) node[cur].link = q; else { int clone = sz ++; node[clone].link = node[q].link; memcpy(node[clone].next, node[q].next, sizeof(node[q].next)); node[clone].len = node[p].len + 1; for (; ~p && node[p].next[c] == q; p = node[p].link) { node[p].next[c] = clone; } node[q].link = node[cur].link = clone; } } last = cur; } int c[N], p[N]; ll getAns() { mset(c, 0); for (int i = 0; i < sz; i ++) c[node[i].len] ++; for (int i = 1; i <= sz; i ++) c[i] += c[i - 1]; for (int i = 0; i < sz; i ++) p[-- c[node[i].len]] = i; for (int i = sz - 1; i >= 0; i --) { int cur = p[i]; if (cur == 0) continue; umax(node[node[cur].link].r, node[cur].r); } ll ans = 0; for (int i = 1; i < sz; i ++) { if (node[i].r <= len) ans += node[i].len - node[node[i].link].len; } return ans; } private: const static int SZ = 27; struct State { int len, link; int r; int next[SZ]; }; State node[N]; int sz, last; }; SAM sam; char s[N]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int n; cas() { cin >> n; sam.init(); for (int i = -1; i < n; i ++) { scanf("%s", s); if (i < 0) len = strlen(s); for (int j = 0; s[j]; j ++) { sam.add(s[j] - 'a'); } sam.add(26); } printf("Case %d: %I64d\n", ++ cas, sam.getAns()); } return 0; }