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 }

 

posted @ 2018-01-16 11:42  p0ny  阅读(133)  评论(0编辑  收藏  举报