zoukankan      html  css  js  c++  java
  • SPOJ REPEATS

    Description

    求一个字符串内重复次数最多的连续字串。

    Solution

    丢一个hihocoder的链接

    先考虑如何如何求一个串给定的串的最大重复次数,枚举一个可能的循环节长度 (l),然后求原串和原串去掉前 (l) 个字符后两个串的 (lcp)(最长公共前缀),如果能完全匹配上,就是一个循环节,且循环次数为 (lcp(l,i)/l + 1)

    所以我们可以先枚举一个可能的长度 (l),然后再枚举起点 (i),然后通过求 (suf[i],suf[i+l])(lcp) 进行判断。但是其实并不需要枚举每个 (i),只需要枚举 (l) 的整数倍。

    如果最优串的开始位置恰好在 (l) 的倍数上,那我们找到的最大的 (k) 就是正确答案。

    如果不在 (l) 的倍数上,那么只可能是在 (i-(l-lcp(i,i+l)\% l))。(具体证明戳上面的链接)

    Code

    #include <algorithm>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    const int _ = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    int N, rk[_], sa[_], height[_];
    char s[_];
    
    void SA() {
      int M = 125, p;
      static int buc[_], id[_], fir[_], oldrk[_];
      fill(buc + 1, buc + M + 1, 0);
      for (int i = 1; i <= N; ++i) ++buc[rk[i] = s[i]];
      for (int i = 1; i <= M; ++i) buc[i] += buc[i - 1];
      for (int i = N; i >= 1; --i) sa[buc[rk[i]]--] = i;
      for (int len = 1; len < N; len <<= 1, M = p) {
        p = 0;
        for (int i = N; i > N - len; --i) id[++p] = i;
        for (int i = 1; i <= N; ++i)
          if (sa[i] > len) id[++p] = sa[i] - len;
        fill(buc + 1, buc + M + 1, 0);
        for (int i = 1; i <= N; ++i) ++buc[fir[i] = rk[id[i]]];
        for (int i = 1; i <= M; ++i) buc[i] += buc[i - 1];
        for (int i = N; i >= 1; --i) sa[buc[fir[i]]--] = id[i];
        copy(rk + 1, rk + N + 1, oldrk + 1);
        p = 0;
        for (int i = 1; i <= N; ++i) {
          if (i == 1)
            rk[sa[i]] = ++p;
          else {
            int x = sa[i], y = sa[i - 1];
            if (oldrk[x] == oldrk[y] && oldrk[x + len] == oldrk[y + len])
              rk[sa[i]] = p;
            else
              rk[sa[i]] = ++p;
          }
        }
        if (p == N) break;
      }
      for (int i = 1, k = 0; i <= N; ++i) {
        if (rk[i] == 1)
          k = 0;
        else {
          if (k > 0) --k;
          int j = sa[rk[i] - 1];
          while (i + k <= N && j + k <= N && s[i + k] == s[j + k]) ++k;
        }
        height[rk[i]] = k;
      }
    }
    
    namespace ST {
    int st[_][21], lg[_];
    void init() {
      lg[0] = -1;
      for (int i = 1; i <= N; ++i) st[i][0] = height[i], lg[i] = lg[i >> 1] + 1;
      for (int j = 1; j <= 20; ++j)
        for (int i = 1; i + (1 << j) - 1 <= N; ++i)
          st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
    }
    int query(int x, int y) {
      if (x > y) swap(x, y);
      ++x;
      int s = lg[y - x + 1];
      return min(st[x][s], st[y - (1 << s) + 1][s]);
    }
    }  // namespace ST
    
    int lcp(int l, int r) {
      int x = rk[l], y = rk[r];
      return ST::query(x, y);
    }
    
    int ans = 0;
    void solve() {
      for (int L = 1; L <= N; L++) {
        for (int i = 1; i + L <= N; i += L) {
          int R = lcp(i, i + L);
          ans = max(ans, R / L + 1);
          if (i >= L - R % L) {
            ans = max(lcp(i - L + R % L, i + R % L) / L + 1, ans);
          }
        }
      }
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("repeat.in", "r", stdin);
      freopen("repeat.out", "w", stdout);
    #endif
      int T;
      scanf("%d", &T);
      while (T--) {
        ans = 0;
        scanf("%d", &N);
        for (int i = 1; i <= N; ++i) {
          char tmp[5];
          scanf("%s", tmp);
          s[i] = tmp[0];
        }
        SA();
        ST::init();
        solve();
        printf("%d
    ", ans);
      }
      return 0;
    }
    
  • 相关阅读:
    之前总结的,现在要找工作了,给大家分享一下
    numpy总结
    django知识分支_1
    Django小总结
    ORM
    百度在线编辑器 配置修改
    百度在线编辑器
    TP5 路由使用
    cache 订单队列
    绘制静态地图API-高德地图
  • 原文地址:https://www.cnblogs.com/newbielyx/p/12166277.html
Copyright © 2011-2022 走看看