danielvitor23

Periodic Substring

Aug 10th, 2023 (edited)
981
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.42 KB | None | 0 0
  1. #include <bits/stdc++.h>
  2. #define fi first
  3. #define se second
  4. using namespace std;
  5. const int INF = 1e9;
  6.  
  7. template<typename T> struct rmq {
  8.     vector<T> v;
  9.     int n; static const int b = 30;
  10.     vector<int> mask, t;
  11.  
  12.     int op(int x, int y) { return v[x] <= v[y] ? x : y; }
  13.     int msb(int x) { return __builtin_clz(1)-__builtin_clz(x); }
  14.     int small(int r, int sz = b) { return r-msb(mask[r]&((1<<sz)-1)); }
  15.     rmq() {}
  16.     rmq(const vector<T>& v_) : v(v_), n(v.size()), mask(n), t(n) {
  17.         for (int i = 0, at = 0; i < n; mask[i++] = at |= 1) {
  18.             at = (at<<1)&((1<<b)-1);
  19.             while (at and op(i-msb(at&-at), i) == i) at ^= at&-at;
  20.         }
  21.         for (int i = 0; i < n/b; i++) t[i] = small(b*i+b-1);
  22.         for (int j = 1; (1<<j) <= n/b; j++) for (int i = 0; i+(1<<j) <= n/b; i++)
  23.             t[n/b*j+i] = op(t[n/b*(j-1)+i], t[n/b*(j-1)+i+(1<<(j-1))]);
  24.     }
  25.     int index_query(int l, int r) {
  26.         if (r-l+1 <= b) return small(r, r-l+1);
  27.         int x = l/b+1, y = r/b-1;
  28.         if (x > y) return op(small(l+b-1), small(r));
  29.         int j = msb(y-x+1);
  30.         int ans = op(small(l+b-1), op(t[n/b*j+x], t[n/b*j+y-(1<<j)+1]));
  31.         return op(ans, small(r));
  32.     }
  33.     T query(int l, int r) { return v[index_query(l, r)]; }
  34. };
  35.  
  36. vector<int> sort_cyclic_shifts(string const& s) {
  37.   int n = s.size();
  38.   const int alphabet = 256;
  39.  
  40.   vector<int> p(n), c(n), cnt(max(alphabet, n), 0);
  41.   for (int i = 0; i < n; i++)
  42.     cnt[s[i]]++;
  43.   for (int i = 1; i < alphabet; i++)
  44.     cnt[i] += cnt[i-1];
  45.   for (int i = 0; i < n; i++)
  46.     p[--cnt[s[i]]] = i;
  47.   c[p[0]] = 0;
  48.   int classes = 1;
  49.   for (int i = 1; i < n; i++) {
  50.     if (s[p[i]] != s[p[i-1]])
  51.         classes++;
  52.     c[p[i]] = classes - 1;
  53.   }
  54.  
  55.   vector<int> pn(n), cn(n);
  56.   for (int h = 0; (1 << h) < n; ++h) {
  57.     for (int i = 0; i < n; ++i) {
  58.       pn[i] = p[i] - (1 << h);
  59.       if (pn[i] < 0)
  60.         pn[i] += n;
  61.     }
  62.  
  63.     fill(cnt.begin(), cnt.begin() + classes, 0);
  64.     for (int i = 0; i < n; i++)
  65.       cnt[c[pn[i]]]++;
  66.     for (int i = 1; i < classes; i++)
  67.       cnt[i] += cnt[i-1];
  68.     for (int i = n-1; i >= 0; i--)
  69.       p[--cnt[c[pn[i]]]] = pn[i];
  70.     cn[p[0]] = 0;
  71.     classes = 1;
  72.     for (int i = 1; i < n; i++) {
  73.       pair<int, int> cur = {c[p[i]], c[(p[i] + (1 << h)) % n]};
  74.       pair<int, int> prev = {c[p[i-1]], c[(p[i-1] + (1 << h)) % n]};
  75.       if (cur != prev)
  76.         ++classes;
  77.       cn[p[i]] = classes - 1;
  78.     }
  79.     c.swap(cn);
  80.   }
  81.  
  82.   return p;
  83. }
  84.  
  85. vector<int> suffix_array_construction(string s) {
  86.   s += "$";
  87.   vector<int> sorted_shifts = sort_cyclic_shifts(s);
  88.   sorted_shifts.erase(sorted_shifts.begin());
  89.   return sorted_shifts;
  90. }
  91.  
  92. vector<int> lcp_construction(const string &s, const vector<int> &p) {
  93.   int n = s.size();
  94.  
  95.   vector<int> rank(n, 0);
  96.   for (int i = 0; i < n; ++i) {
  97.     rank[p[i]] = i;
  98.   }
  99.  
  100.   int k = 0;
  101.   vector<int> lcp(n-1, 0);
  102.   for (int i = 0; i < n; ++i) {
  103.     if (rank[i] == n-1) {
  104.       k = 0;
  105.       continue;
  106.     }
  107.  
  108.     int j = p[rank[i] + 1];
  109.     while (i + k < n and j + k < n and s[i + k] == s[j + k])
  110.       ++k;
  111.     lcp[rank[i]] = k;
  112.     if (k) --k;
  113.   }
  114.  
  115.   return lcp;
  116. }
  117.  
  118. int n;
  119. int ans = -INF;
  120.  
  121. vector<int> SA, lcp, rnk;
  122. rmq<int> ST;
  123.  
  124. // dfs na suffix tree
  125. void dfs(int L, int R, int p, pair<int, int> &nearest, set<int> &st) {
  126.   int ext = L != R ? ST.query(L, R-1) : n - SA[L];
  127.  
  128.   int l = L, r = R;
  129.   if (SA[L]+ext == n) {
  130.     st.insert(SA[L]);
  131.     L++;
  132.   }
  133.  
  134.   set<int> my_set;
  135.   pair<int, int> my_nearest({-INF, INF});
  136.  
  137.   while (L <= R) {
  138.     int idx = L != R ? ST.index_query(L, R-1) : -1;
  139.     if (idx == -1 or lcp[idx] != ext) idx = R;
  140.  
  141.     dfs(L, idx, ext, my_nearest, my_set);
  142.  
  143.     if (my_set.size() > st.size()) {
  144.       swap(st, my_set);
  145.     }
  146.  
  147.     int diff = abs(my_nearest.fi - my_nearest.se);
  148.     if (diff < abs(nearest.fi - nearest.se)) {
  149.       nearest = my_nearest;
  150.     }
  151.  
  152.     for (int x : my_set) {
  153.       st.insert(x);
  154.       auto aux = st.lower_bound(x);
  155.       auto it = aux;
  156.  
  157.       if (it != prev(st.end())) {
  158.         int nxt = *next(it);
  159.         int diff = abs(x - nxt);
  160.         if (diff < abs(nearest.fi - nearest.se)) {
  161.           nearest = {x, nxt};
  162.         }
  163.       }
  164.  
  165.       it = aux;
  166.       if (it != st.begin()) {
  167.         int prv = *prev(it);
  168.         int diff = abs(x - prv);
  169.         if (diff < abs(nearest.fi - nearest.se)) {
  170.           nearest = {x, prv};
  171.         }
  172.       }
  173.     }
  174.  
  175.     my_set.clear();
  176.     my_nearest = {-INF, INF};
  177.     L = idx+1;
  178.   }
  179.  
  180.   int ll = nearest.fi, rr = nearest.se;
  181.   if (ll > rr) swap(ll, rr);
  182.   if (l != r and ll != rr) {
  183.     ans = max(ans,
  184.       ST.query(l, r-1) / (rr - ll) + 1
  185.     );
  186.   }
  187.   // cout << l << ' ' << r << " -> " << ll << ' ' << rr << ' ' <<
  188.   //   (ST.query(l, r-1) / (rr - ll) + 1) <<  '\n';
  189. }
  190.  
  191. int main() {
  192.   cin.tie(0)->sync_with_stdio(0);
  193.  
  194.   string s; cin >> s;
  195.   n = s.size();
  196.   rnk.assign(n, 0);
  197.  
  198.   SA = suffix_array_construction(s);
  199.   lcp = lcp_construction(s, SA);
  200.  
  201.   for (int i = 0; i < (int)SA.size(); ++i) {
  202.     // cout << i << ' ' << SA[i] << ' ' << s.substr(SA[i]) << '\n';
  203.     rnk[SA[i]] = i;
  204.   }
  205.  
  206.   // for (int i = 0; i < (int)lcp.size(); ++i) {
  207.   //   cout << lcp[i] << '\n';
  208.   // }
  209.  
  210.   ST = rmq<int>(lcp);
  211.  
  212.   set<int> my_set;
  213.   pair<int, int> nearest({-INF, INF});
  214.   dfs(0, n-1, 0, nearest, my_set);
  215.  
  216.   // for (int x : my_set) {
  217.   //   cout << x << ' ';
  218.   // } cout << '\n';
  219.  
  220.   // cout << nearest.fi << ' ' << nearest.se << '\n';
  221.  
  222.   cout << ans << '\n';
  223. }
  224. /*
  225. ababba
  226.  
  227. 0. a
  228. 1. aba
  229. 2. abba
  230. 3. ba
  231. 4. babba
  232. 5. bba
  233.  
  234. */
Advertisement
Add Comment
Please, Sign In to add comment