1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N = 2e5+5; typedef long long int64; int n, m, q; char s[N]; namespace sam { int tot = 1, last = 1, ch[N][10], fa[N], len[N], pos[N]; void insert(int c) { int cur = ++tot, pre = last; last = cur; len[cur] = len[pre]+1; pos[cur] = len[cur]; while(pre&&!ch[pre][c]) ch[pre][c] = cur, pre = fa[pre]; if(!pre) return void(fa[cur] = 1); int x = ch[pre][c]; if(len[pre]+1 == len[x]) return (void)(fa[cur] = x); int y = ++tot; fa[y] = fa[x]; fa[x] = fa[cur] = y; pos[y] = pos[cur]; len[y] = len[pre]+1; memcpy(ch[y], ch[x], sizeof(ch[y])); while(pre&&ch[pre][c] == x) ch[pre][c] = y, pre = fa[pre]; } }
int tot, root[N], val[N<<5], ls[N<<5], rs[N<<5]; void add(int &x, int l, int r, int pos) { if(!x) x = ++tot; ++val[x]; if(l == r) return; int mid = (l+r)>>1; if(pos <= mid) add(ls[x], l, mid, pos); else add(rs[x], mid+1, r, pos); } int merge(int x, int y) { if(!x||!y) return x|y; int z = ++tot; val[z] = val[x]+val[y]; ls[z] = merge(ls[x], ls[y]); rs[z] = merge(rs[x], rs[y]); return z; } int query(int x, int l, int r, int ql, int qr) { if(!x||(ql <= l&&r <= qr)) return val[x]; int mid = (l+r)>>1, ret = 0; if(ql <= mid) ret += query(ls[x], l, mid, ql, qr); if(qr > mid) ret += query(rs[x], mid+1, r, ql, qr); return ret; } int tax[N], p[N]; int main() { scanf("%d%s%d", &n, s+1, &q); reverse(s+1, s+1+n); for(int i = 1; i <= n; ++i) sam::insert(s[i]-'0'), add(root[sam::last], 1, n, i); for(int i = 1; i <= sam::tot; ++i) ++tax[sam::len[i]]; for(int i = 1; i <= sam::tot; ++i) tax[i] += tax[i-1]; for(int i = 1; i <= sam::tot; ++i) p[tax[sam::len[i]]--] = i; for(int i = sam::tot; i > 1; --i) sam::pos[sam::fa[p[i]]] = max(sam::pos[sam::fa[p[i]]], sam::pos[p[i]]), root[sam::fa[p[i]]] = merge(root[sam::fa[p[i]]], root[p[i]]); while(q--) { scanf("%s", s+1); m = strlen(s+1); reverse(s+1, s+1+m); int x = 1, lcs = 0, p = 1; int64 ans = 0; for(int i = 1; i <= m; ++i) { while(x&&!sam::ch[x][s[i]-'0']) x = sam::fa[x], lcs = sam::len[x]; if(!x) x = 1, lcs = 0; else x = sam::ch[x][s[i]-'0'], ++lcs; if(lcs == m) break; } if(lcs == m) p = sam::pos[x]+1, ans += m, x = sam::fa[x]; else if(x != 1) ans += 1ll*(lcs-sam::len[sam::fa[x]])*query(root[x], 1, n, p, n), x = sam::fa[x]; while(x != 1) ans += 1ll*(sam::len[x]-sam::len[sam::fa[x]])*query(root[x], 1, n, p, n), x = sam::fa[x]; ans += query(root[x], 1, n, p, n); printf("%lld\n", ans); } return 0; }
|