BZOJ - 4516: [Sdoi2016]生成魔咒
4516: [Sdoi2016]生成魔咒
题意:每次向字符串后添加一个字符,并回答此时子串的数目。
题解:咱把字符串倒过来就变成了每次向头插入一个字符,也就是每次增加一个后缀,然后构建出后缀数组。对新字符串(倒过来的原字符串)咱顺序处理。考虑当前的后缀$suffix(i)$对答案的贡献就是$|suffix(i)|- \max \{lcp(suffix(i), suffix(j)|(i<j)\}$。用链表维护,做完一个就删掉。最后再倒序加一遍然后输出答案。
1 #include<map> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 int n, a[100005]; 8 long long ans[100005]; 9 template < int N > 10 struct SuffixArray { 11 int sa[N], rk[N], ht[N], t[N<<1], s[N<<1], p[N], cnt[N], cur[N], nxt[N], pre[N]; 12 #define pushL(x) sa[cur[s[x]]++] = x 13 #define pushS(x) sa[cur[s[x]]--] = x 14 #define sort(v) fill_n(sa, n, -1); fill_n(cnt, m, 0); \ 15 for (int i = 0; i < n; ++i) ++cnt[s[i]]; \ 16 for (int i = 1; i < m; ++i) cnt[i] += cnt[i-1]; \ 17 for (int i = 0; i < m; ++i) cur[i] = cnt[i] - 1; \ 18 for (int i = n1 - 1; ~i; --i) pushS(v[i]); \ 19 for (int i = 1; i < m; ++i) cur[i] = cnt[i-1]; \ 20 for (int i = 0; i < n; ++i) if (sa[i] > 0 && t[sa[i]-1]) pushL(sa[i]-1); \ 21 for (int i = 0; i < m; ++i) cur[i] = cnt[i] - 1; \ 22 for (int i = n - 1; ~i; --i) if (sa[i] > 0 && !t[sa[i]-1]) pushS(sa[i]-1) 23 void sais(int n, int m, int *s, int *t, int *p) { 24 int n1 = t[n-1] = 0, ch = rk[0] = -1, *s1 = s + n; 25 for (int i = n - 2; ~i; --i) t[i] = s[i+1] == s[i] ? t[i+1] : s[i] > s[i+1]; 26 for (int i = 1; i < n; ++i) rk[i] = t[i-1] && !t[i] ? (p[n1] = i, n1++) : -1; 27 sort(p); 28 for (int i = 0, x, y; i < n; ++i) if (~(x = rk[sa[i]])) { 29 if (ch < 1 || p[x+1] - p[x] != p[y+1] - p[y]) ++ch; 30 else for (int j = p[x], k = p[y]; j <= p[x+1]; ++j, ++k) 31 if ((s[j]<<1|t[j]) != (s[k]<<1|t[k])) {++ch; break;} 32 s1[y=x] = ch; 33 } 34 if (ch + 1 < n1) sais(n1, ch + 1, s1, t + n, p + n1); 35 else for (int i = 0; i < n1; ++i) sa[s1[i]] = i; 36 for (int i = 0; i < n1; ++i) s1[i] = p[sa[i]]; 37 sort(s1); 38 } 39 template < class T > 40 inline int map(int n, const T *str) { 41 int m = *max_element(str, str + n); 42 fill_n(rk, m + 1, 0); 43 for (int i = 0; i < n; ++i) rk[str[i]] = 1; 44 for (int i = 0; i < m; ++i) rk[i+1] += rk[i]; 45 for (int i = 0; i < n; ++i) s[i] = rk[str[i]] - 1; 46 return rk[m]; 47 } 48 template < class T > 49 void init(int n, const T *str) { 50 int m = map(n, str); 51 sais(n, m, s, t, p); 52 for (int i = 0; i < n; ++i) rk[sa[i]] = i; 53 for (int i = 0, h = ht[0] = 0; i < n - 1; ++i) { 54 int j = sa[rk[i]-1]; 55 while (i + h < n && j + h < n && s[i+h] == s[j+h]) ++h; 56 if ((ht[rk[i]] = h)) --h; 57 } 58 for (int i = 0; i < n - 1; ++i) nxt[i] = i + 1; 59 for (int i = 1; i < n; ++i) pre[i] = i - 1; 60 } 61 template < class T > 62 void solve(int n, const T *str) { 63 init(n, str); 64 for (int i = 0; i < n - 1; ++i) { 65 int r = rk[i]; 66 ans[i] = n - i - 1 - max(ht[r], ht[nxt[r]]); 67 ht[nxt[r]] = min(ht[nxt[r]], ht[r]); 68 ht[r] = 0; 69 if (r) nxt[pre[r]] = nxt[r]; 70 pre[nxt[r]] = pre[r]; 71 } 72 for (int i = n - 2; ~i; --i) ans[i] += ans[i+1]; 73 for (int i = n - 2; ~i; --i) printf("%lld\n", ans[i]); 74 } 75 }; 76 inline int idx(int x) { 77 static map < int , int > h; static int H = 0; 78 return h.count(x) ? h[x] : h[x] = ++H; 79 } 80 inline char nc() { 81 return getchar(); 82 static char b[1<<17],*s=b,*t=b; 83 return s==t&&(t=(s=b)+fread(b,1,1<<17,stdin),s==t)?-1:*s++; 84 } 85 inline void read(int &x) { 86 char b = nc(); x = 0; 87 for (; !isdigit(b); b = nc()); 88 for (; isdigit(b); b = nc()) x = x * 10 + b - '0'; 89 } 90 SuffixArray < 100005 > SA; 91 int main() { 92 read(n); 93 for (int i = n - 1; ~i; --i) 94 read(a[i]), a[i] = idx(a[i]); 95 a[n] = 0; SA.solve(n + 1, a); 96 return 0; 97 }