• SP687 REPEATS


    给定字符串,求重复次数最多的连续重复子串。

    题目很简单,被细节坑惨了。。。

    前置的一个推论:请看这里。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 50010;
    
    struct String {
        char s[N]; int st[N][17];
        
        int n, m, sa[N], tp[N], rk[N], _rk[N], bin[N], height[N];
        
        void clear () {
            memset (s, 0, sizeof (s));
            memset (sa, 0, sizeof (sa));
            memset (tp, 0, sizeof (tp));
            memset (rk, 0, sizeof (rk));
            memset (st, 0, sizeof (st));
            memset (_rk, 0, sizeof (_rk));
            memset (bin, 0, sizeof (bin));
            memset (height, 0, sizeof (height));
        }
        
        void base_sort () {
            for (int i = 0; i <= m; ++i) bin[i] = 0;
            for (int i = 1; i <= n; ++i) bin[rk[tp[i]]]++;
            for (int i = 1; i <= m; ++i) bin[i] += bin[i - 1];
            for (int i = n; i >= 1; --i) sa[bin[rk[tp[i]]]--] = tp[i];
        }
        
        void suffix_sort () {
            m = 255; ;
            for (int i = 1; i <= n; ++i) {
                tp[i] = i, rk[i] = s[i];
            }
            base_sort ();
            for (int w = 1; w <= n; w <<= 1) {
                int cnt = 0;
                for (int i = n - w + 1; i <= n; ++i) tp[++cnt] = i;
                for (int i = 1; i <= n; ++i) if (sa[i] > w) tp[++cnt] = sa[i] - w;
                base_sort ();
                memcpy (_rk, rk, sizeof (rk));
                rk[sa[1]] = cnt = 1;
                for (int i = 2; i <= n; ++i) {
                    rk[sa[i]] = _rk[sa[i]] == _rk[sa[i - 1]] && _rk[sa[i] + w] == _rk[sa[i - 1] + w] ? cnt : ++cnt;
                }
                if (cnt == n) break;
                m = cnt;
            }
            int k = 0;
            for (int i = 1; i <= n; ++i) {
                if (k != 0) --k;
                int j = sa[rk[i] - 1];
                while (s[i + k] == s[j + k]) ++k;
                height[rk[i]] = k; 
            }
            int mx = log2 (n);
            for (int i = 1; i <= n; ++i) {
                st[i][0] = height[i];
            }
            for (int i = 1; i <= mx; ++i) {
                for (int j = 1; j + (1 << i) - 1 <= n; ++j) {
                    st[j][i] = min (st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
                }
            }
        } 
        
        int lcp (int l, int r) {
            if (l == r) return n - l + 1;
            l = rk[l], r = rk[r];
            if (l > r) swap (l, r); ++l;
            if (l > r) return 0;
            int mx = log2 (r - l + 1);
            return min (st[l][mx], st[r - (1 << mx) + 1][mx]);
        }
    }s1, s2;
    
    int T, n; char s[N];
    
    int main () {
        cin >> T;
        while (T--) {
        	int ans = 0;
            cin >> n; s1.n = s2.n = n;
            s1.clear (); s2.clear ();
            for (int i = 1; i <= n; ++i) {
                cin >> s[i];
                s1.s[i] = s[i];
                s2.s[n - i + 1] = s[i];
            }
            s1.suffix_sort ();
            s2.suffix_sort ();
            for (int len = 1; len <= n; ++len) {//枚举重复子串的长度 
                for (int p = 1; p + len <= n; p += len) {
                    int K = s1.lcp (p, p + len) + s2.lcp (n - (p) + 1, n - (p + len) + 1) - 1;
                    ans = max (ans, K / len + 1);
                }
            }
            cout << max (ans, 1) << endl;
        }
    }
    
  • 相关阅读:
    mini2440 UBoot启动过程完全分析
    Linux Shell常用命令学习(1)
    S3C6410启动模式介绍
    漫画与新媒体的传播思考
    注册表修改启动项
    邮件主题是乱码的原因gbk 在utf8 显示问题
    移动 电话费 套餐
    java 异常的问题讨论
    领结的打法
    c# 字符之间的转换
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10641837.html
Copyright © 2020-2023  润新知