zoukankan      html  css  js  c++  java
  • POJ 3693 Maximum repetition substring(后缀数组)

    Description

    The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1.

    Given a string containing lowercase letters, you are to find a substring of it with maximum repetition number.

    Input

    The input consists of multiple test cases. Each test case contains exactly one line, which
    gives a non-empty string consisting of lowercase letters. The length of the string will not be greater than 100,000.

    The last test case is followed by a line containing a '#'.

    Output

    For each test case, print a line containing the test case number( beginning with 1) followed by the substring of maximum repetition number. If there are multiple substrings of maximum repetition number, print the lexicographically smallest one.

    题目大意:给一个字符串,求重复次数最多的连续重复子串,如有多个答案输出字典序最小的。

    思路:对于一个由长度为L的字符串重复R次形成的子串,那么对于s[0]、s[L]、s[2*L]……,该子串必然包含其中的两个字符

    那么,我们从1~n穷举长度L

    对于每一个s[i*L]、s[(i+1)*L]看看它们能往前和往后同时匹配多长

    记这个长度为K,那么K/L+1就是可以重复的次数(对于一个字符串如果他是由R个长度为L的字符串重复形成的,那么必然有lcp(suffix(0), suffix(L))==L*(R-1))

    然后,从两个点往后匹配好求,但往前匹配就不好办了,虽然可以把字符串反过来再弄一个后缀数组,但是这不够优美。

    比较优美的方法就是,对于某个连续重复子串,假设它的包含的最前面的两个是s[i*L]和s[(i+1)*L],设p=L-lcp%L(当lcp mod L ≠ 0)

    那么只需要测试lcp(i*L-p, (i+1)*L-p)就行了,因为再往前,重复的次数也不会增加。

    然后我们就可以得到最大重复次数了。

    但是题目要求的是字典序最小的答案耶……要在算重复次数的时候也算出来好像很有难度(应该说是很麻烦,大概就是DISCUSS里面那个说3个RMQ的人……)

    但是,我们再算最大重复次数的时候,把长度也算出来,设为K

    那么只要遍历一下字符串,把lcp(i, i + K / R) ≥ K - K / R的找出来,这些都是符合条件的答案开头,因为有后缀数组,直接找rank最小的就行了。

    这样,这题就做完了。

    代码(313MS):

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <cstring>
      5 using namespace std;
      6 
      7 const int MAXN = 100010;
      8 
      9 char s[MAXN];
     10 int sa[MAXN], height[MAXN], rank[MAXN], c[MAXN], tmp[MAXN];
     11 int n;
     12 
     13 void makesa(int m) {
     14     memset(c, 0, m * sizeof(int));
     15     for(int i = 0; i < n; ++i) ++c[rank[i] = s[i]];
     16     for(int i = 1; i < m; ++i) c[i] += c[i - 1];
     17     for(int i = 0; i < n; ++i) sa[--c[rank[i]]] = i;
     18     for(int k = 1; k < n; k <<= 1) {
     19         for(int i = 0; i < n; ++i) {
     20             int j = sa[i] - k;
     21             if(j < 0) j += n;
     22             tmp[c[rank[j]]++] = j;
     23         }
     24         int j = c[0] = sa[tmp[0]] = 0;
     25         for(int i = 1; i < n; ++i) {
     26             if(rank[tmp[i]] != rank[tmp[i - 1]] || rank[tmp[i] + k] != rank[tmp[i - 1] + k])
     27                 c[++j] = i;
     28             sa[tmp[i]] = j;
     29         }
     30         memcpy(rank, sa, n * sizeof(int));
     31         memcpy(sa, tmp, n * sizeof(int));
     32     }
     33 }
     34 
     35 void calheight() {
     36     for(int i = 0, k = 0; i < n; height[rank[i++]] = k) {
     37         if(k > 0) --k;
     38         int j = sa[rank[i] - 1];
     39         while(s[i + k] == s[j + k]) ++k;
     40     }
     41 }
     42 
     43 int logn[MAXN];
     44 int best[20][MAXN];
     45 
     46 void initRMQ() {
     47     logn[0] = -1;
     48     for(int i = 1; i <= n; ++i)
     49         logn[i] = (i & (i - 1)) == 0 ? logn[i - 1] + 1 : logn[i - 1];
     50     for(int i = 1; i <= n; ++i) best[0][i] = height[i];
     51     for(int i = 1; i <= logn[n]; ++i) {
     52         int ed = n - (1 << i) + 1;
     53         for(int j = 1; j <= ed; ++j)
     54             best[i][j] = min(best[i - 1][j], best[i - 1][j + (1 << (i - 1))]);
     55     }
     56 }
     57 
     58 int lcp(int a, int b) {
     59     a = rank[a], b = rank[b];
     60     if(a > b) swap(a, b);
     61     ++a;
     62     int t = logn[b - a + 1];
     63     return min(best[t][a], best[t][b - (1 << t) + 1]);
     64 }
     65 
     66 void solve() {
     67     int ans = 0, ansL = 1, ansR = 1;
     68     for(int i = 1; i < n - 1; ++i) if(s[i] < s[ans]) ans = i;
     69     for(int i = 1; i < n; ++i) {
     70         for(int j = 0; j + i < n - 1; j += i) {
     71             int t = lcp(j, j + i), p = 0;
     72             if(t % i) {
     73                 p = i - t % i;
     74                 if(j < p) p = 0;
     75                 t = max(t, lcp(j - p, j + i - p));
     76             }
     77             if(t / i + 1 > ansR || (t / i + 1 == ansR && rank[j] < rank[ans])) {
     78                 ans = j - p;
     79                 ansR = t / i + 1;
     80                 ansL = ansR * i;
     81             }
     82         }
     83     }
     84     for(int i = 0; i < n - 1; ++i)
     85         if(lcp(i, i + ansL / ansR) >= ansL - ansL / ansR && rank[i] < rank[ans]) ans = i;
     86     for(int i = ans; i < ans + ansL; ++i) putchar(s[i]);
     87     puts("");
     88 }
     89 
     90 int main() {
     91     int kase = 0;
     92     while(scanf("%s", s) != EOF) {
     93         if(*s == '#') break;
     94         n = strlen(s) + 1;
     95         makesa(128);
     96         calheight();
     97         initRMQ();
     98         printf("Case %d: ", ++kase);
     99         solve();
    100     }
    101 }
    View Code
  • 相关阅读:
    对于.net config文件中加密使用
    删除windows不想要的服务
    ora12514: tns: 监听程序当前无法识别连接描述符中请求的服务
    读《.NET设计规范》笔记
    创建服务总结
    加载XML文档
    XMLHttpRequest对象的使用
    ReportView控件的使用
    C#代码的编译过程
    Qt vs设置可执行程序图标
  • 原文地址:https://www.cnblogs.com/oyking/p/3537078.html
Copyright © 2011-2022 走看看