• 重复次数最多的连续重复子串


    题目链接:https://cn.vjudge.net/contest/318888#problem/G

    题意:

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

    思路:

    我们先看下罗老师的论文中给出的思路

    虽然话很短,但是很难理解。我就讲一下我刚开始无法理解的一些地方吧,既方便我巩固也方便我今后复习。

    1、为什么连续出现了K/L+1次?

    我们先看这个图片上的例子

    r[6] :  a a b a a b a a b a b

    r[9] :  a a b a a b a b

    先考虑往后匹配可以知道K=9,K/L只是在 r[9]之后重复出现的次数 再加上 r[6]->r[9]之间重复出现的一次

    所以是 K/L+1

    2、为什么S肯定包括了字符r[0],r[L],r[2*L] 中某相邻两个

    由于当前S是有两个长度为L的连续重复子串拼接而成的,那意味着S[i]和S[i+L](0≤i<L)必定是一样的字符

    而这两个字符位置相差L

    而字符r[0],r[L],r[L*2],r[L*3],......中相邻两个的位置差均为L

    3、为什么只须看字符r[L*i]和r[L*(i+1)]往前和往后各能匹配到多远

    其实,当枚举的重复子串长度为i时,我们在枚举r[i*j]和r[i*(j+1)]的过程中,必然可以出现r[i*j]在第一个重复子串里,而r[i*(j+1)]在第二个重复子串里的这种情况,如果此时r[i*j]是第一个重复子串的首字符,这样直接用公共前缀k除以i并向下取整就可以得到最后结果。但如果r[i*j]如果不是首字符,这样算完之后结果就有可能偏小,因为r[i*j]前面可能还有少许字符也能看作是第一个重复子串里的。


    于是,我们不妨先算一下,从r[i*j]开始,除匹配了k/i个重复子串,还剩余了几个字符,剩余的自然是k%i个字符。如果说r[i*j]的前面还有i-k%i个字符完成匹配的话,这样就相当于利用多余的字符还可以再匹配出一个重复子串,于是我们只要检查一下从r[i*j-(i-k%i)]和r[i*(j+1)-(i-k%i)]开始是否有i-k%i个字符能够完成匹配即可,也就是说去检查这两个后缀的最长公共前缀是否比i-k%i大即可。
    当然如果公共前缀不比i-k%i小,自然就不比i小,因为后面的字符都是已经匹配上的,所以为了方便编写,程序里面就直接去看是否会比i小就可以了。

      1 #include <stdio.h>
      2 #include <iostream>
      3 #include <algorithm>
      4 #include <string.h>
      5 #include <stdlib.h>
      6 #include <math.h>
      7 #include <queue>
      8 #include <set>
      9 
     10 #define INF 0x3f3f3f3f
     11 #define pii pair<int,int>
     12 #define LL long long
     13 using namespace std;
     14 typedef unsigned long long ull;
     15 const int maxn = 5e4 + 10;
     16 
     17 char s[maxn];
     18 int sa[maxn],t[maxn],t2[maxn],c[maxn];
     19 int Rank[maxn],height[maxn];
     20 int dp[maxn][maxn];
     21 
     22 void build_sa(int n,int m)
     23 {
     24     int i,j,*x=t,*y=t2;
     25     for (i=0;i<m;i++)
     26         c[i] = 0;
     27     for (i=0;i<n;i++)
     28         c[x[i] = s[i]]++;
     29     for (i=1;i<m;i++)
     30         c[i] += c[i-1];
     31     for (i=n-1;i>=0;i--)
     32         sa[--c[x[i]]] = i;
     33     for (int k=1;k<=n;k<<=1)
     34     {
     35         int p = 0;
     36         for (i=n-k;i<n;i++)
     37             y[p++] = i;
     38         for (i=0;i<n;i++)
     39         {
     40             if (sa[i]>=k)
     41                 y[p++] = sa[i]-k;
     42         }
     43         for (i=0;i<m;i++)
     44             c[i] = 0;
     45         for (i=0;i<n;i++)
     46             c[x[y[i]]]++;
     47         for (i=1;i<m;i++)
     48             c[i] += c[i-1];
     49         for (i=n-1;i>=0;i--)
     50             sa[--c[x[y[i]]]] = y[i];
     51         swap(x,y);
     52         p = 1;
     53         x[sa[0]] = 0;
     54         for (i=1;i<n;i++)
     55             x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
     56         if (p>=n)
     57             break;
     58         m = p;
     59     }
     60 }
     61 
     62 void getHeight(int n){
     63     int i,j,k=0;
     64     for (i=1;i<=n;i++){
     65         Rank[sa[i]] = i;
     66     }
     67     for (i=0;i<n;i++){
     68         if (k)
     69             k--;
     70         j = sa[Rank[i]-1];
     71         while (s[i+k] == s[j+k])
     72             k++;
     73         height[Rank[i]] = k;
     74     }
     75 }
     76 
     77 void ST_build(int n){
     78     for (int i=0;i<n;i++){
     79         dp[i][0] = height[i];
     80     }
     81     for (int j=1;(1<<j)<=n;j++){
     82         for (int i=0;(i+(1<<j)-1)<=n;i++){
     83             dp[i][j] = min(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
     84         }
     85     }
     86 }
     87 
     88 int querry(int i,int j){
     89     int l = min(Rank[i],Rank[j]);
     90     int r = max(Rank[i],Rank[j]);
     91     l++;
     92     int cnt = log2(r-l+1),len = 1<<cnt;
     93     return min(dp[l][cnt],dp[r-len+1][cnt]);
     94 }
     95 
     96 
     97 int main(){
     98     int T;
     99     scanf("%d",&T);
    100     while (T--){
    101         int maxx = 1;
    102         int n;
    103         scanf("%d",&n);
    104         getchar();
    105         for (int i=0;i<n;i++){
    106             scanf("%c",&s[i]);
    107             getchar();
    108         }
    109         s[n] = 0;
    110         build_sa(n+1,100);
    111         getHeight(n);
    112         ST_build(n+1);
    113         for (int i=1;i<=n;i++){
    114             for (int j=0;j+i<n;j+=i){
    115                 int ans = querry(j,j+i);
    116                 int k = j-(i-ans%i);
    117                 ans = ans/i+1;
    118                 if (k>=0 && querry(k,k+i)>=i)
    119                     ans++;
    120                 maxx = max(maxx,ans);
    121             }
    122         }
    123         printf("%d
    ",maxx);
    124     }
    125     return 0;
    126 }
  • 相关阅读:
    Anaconda使用命令
    排序算法3--插入排序--希尔排序(缩小增量排序)
    排序算法2--插入排序--折半插入排序
    排序算法1--插入排序--直接插入排序
    排序总结---常用的排序算法总结,java和js实现
    前端兼容性问题
    js对象的几种创建方式和js实现继承的方式[转]
    js原型和原型链[转]
    性能优化的方法
    Http状态码
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/11337510.html
Copyright © 2020-2023  润新知