• POJ 3693 (后缀数组) Maximum repetition substring


    找重复次数最多的字串,如果有多解,要求字典序最小。

    我也是跟着罗穗骞菊苣的论文才刷这道题的。

    首先还是枚举一个循环节的长度L,如果它出现两次的话,一定会包含s[0], s[L], s[2L]这些相邻两个之间。

    然后枚举相邻的两个,尽可能的向前和向后延伸,假设延伸长度为k,则重复次数为k / L + 1

    向后延伸很自然的就是求一次LCP,这个用RMQ预处理一下就可以O(1)查询。

    向前延伸就是考虑到,我们枚举的s[i*L]和s[(i+1)*L]并不一定是字串的开头,所以向前移动i - (k % i)个位置。

    为什么向前移动这么多,就是因为这样的话,LCP的长度就正好是i的整数倍了。

    所以向前移动以后,再求一次LCP,看看能否够i - (k % i)这么多,够的话这个串的重复次数再加1.

    至于要字典序最小,就得用height数组天生自带字典序。把所有重复次数最多的长度记录下来,然后按字典序枚举,只要找到一组就输出。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 
      6 const int maxn = 100000 + 10;
      7 char s[maxn];
      8 int n;
      9 int sa[maxn], rank[maxn], height[maxn];
     10 int t[maxn], t2[maxn], c[256];
     11 
     12 void build_sa(int n, int m)
     13 {
     14     int i, *x = t, *y = t2;
     15     for(i = 0; i < m; i++) c[i] = 0;
     16     for(i = 0; i < n; i++) c[x[i] = s[i]]++;
     17     for(i = 1; i < m; i++) c[i] += c[i - 1];
     18     for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
     19     for(int k = 1; k <= n; k <<= 1)
     20     {
     21         int p = 0;
     22         for(i = n - k; i < n; i++) y[p++] = i;
     23         for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
     24         for(i = 0; i < m; i++) c[i] = 0;
     25         for(i = 0; i < n; i++) c[x[y[i]]]++;
     26         for(i = 1; i < m; i++) c[i] += c[i - 1];
     27         for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
     28         swap(x, y);
     29         p = 1; x[sa[0]] = 0;
     30         for(i = 1; i < n; i++)
     31             x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? p - 1 : p++;
     32         if(p >= n) break;
     33         m = p;
     34     }
     35 }
     36 
     37 void build_height()
     38 {
     39     int k = 0;
     40     for(int i = 1; i <= n; i++) rank[sa[i]] = i;
     41     for(int i = 0; i < n; i++)
     42     {
     43         if(k) k--;
     44         int j = sa[rank[i] - 1];
     45         while(s[i + k] == s[j + k]) k++;
     46         height[rank[i]] = k;
     47     }
     48 }
     49 
     50 int d[maxn][20];
     51 
     52 void init_RMQ()
     53 {
     54     for(int i = 0; i < n; i++) d[i][0] = height[i + 1];
     55     for(int j = 1; (1 << j) <= n; j++)
     56         for(int i = 0; i + (1 << j) - 1 < n; i++)
     57             d[i][j] = min(d[i][j-1], d[i + (1<<(j-1))][j-1]);
     58 }
     59 
     60 int RMQ(int L, int R)
     61 {
     62     int k = 0;
     63     while( (1 << (k+1)) <= (R - L + 1) ) k++;
     64     return min(d[L][k], d[R-(1<<k)+1][k]);
     65 }
     66 
     67 int LCP(int i, int j)
     68 {
     69     i = rank[i] - 1; j = rank[j] - 1;
     70     if(i > j) swap(i, j);
     71     return RMQ(i + 1, j);
     72 }
     73 
     74 int a[maxn], cnt, maxl;
     75 
     76 int main()
     77 {
     78     //freopen("in.txt", "r", stdin);
     79 
     80     int kase = 0;
     81     while(scanf("%s", s) == 1 && s[0] != '#')
     82     {
     83         n = strlen(s);
     84         build_sa(n + 1, 256);
     85         build_height();
     86         init_RMQ();
     87 
     88         cnt = maxl = 0;
     89         for(int i = 1; i < n; i++)
     90         {
     91             for(int j = 0; j + i < n; j += i)
     92             {
     93                 int k = LCP(j, j + i);
     94                 int t = k / i + 1;
     95                 int left = i - (k % i);
     96                 int head = j - left;
     97                 if(head >= 0 && LCP(head, head + i) >= left) t++;
     98                 if(t > maxl)
     99                 {
    100                     cnt = 0;
    101                     a[cnt++] = i;
    102                     maxl = t;
    103                 }
    104                 if(t == maxl) a[cnt++] = i;
    105             }
    106         }
    107 
    108         int len = -1, st;
    109         for(int i = 1; i <= n && len == -1; i++)
    110         {
    111             for(int j = 0; j < cnt; j++)
    112             {
    113                 int l = a[j];
    114                 if(LCP(sa[i], sa[i] + l) >= (maxl - 1) * l)
    115                 {
    116                     len = l;
    117                     st = sa[i];
    118                     break;
    119                 }
    120             }
    121         }
    122 
    123         printf("Case %d: ", ++kase);
    124         for(int i = 0; i < len * maxl; i++) printf("%c", s[st + i]);
    125         puts("");
    126     }
    127 
    128     return 0;
    129 }
    代码君
  • 相关阅读:
    LeetCode 102. 二叉树的层次遍历
    Java | JDK8下的ConcurrentHashMap#get
    Java | JDK8下的ConcurrentHashMap#putValue
    CCF | 小中大
    Jvm | 《深入理解Java虚拟机》读书笔记 |
    Jvm | 《深入理解Java虚拟机》读书笔记 | 线程安全与锁优化
    3. 帧定格和导出单帧
    2. premiere 项目管理
    1.后期特效合成AE概述&&工作流程&&磁盘缓存清理
    贷款减值准备和折现回拨
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4451854.html
Copyright © 2020-2023  润新知