不可重叠最长重复子串

Posted -ackerman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不可重叠最长重复子串相关的知识,希望对你有一定的参考价值。

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

 

题意:

给定一个钢琴的音普序列[值的范围是(1~88)],现在要求找到一个子序列满足

1,长度至少为5

2,序列可以转调,即存在两个子序列,满足一个子序列加/减一个数后可以得到另一个序列

3,两个序列不能有相交的部分。

简单来说就是找最长不重叠的重复子串

 

思路:

首先,我们先想一下如果求不可重叠最长重复子串,我们应该怎么去做呢?

根据罗老师的论文:

技术图片

 

这里的分组的思想应该仔细去体会一下,正是因为分组,所以我们记录每组的后缀位置的最前面和最后面,从而进行判断是否重叠

 

对于第二点要求的转换,即转调条件,一个子序列加/减一个数后可以得到另一个序列实际是两个序列的变化程度是一样的。比如序列1 2 3 4 5 6 7 8 9 10 那么对于这个序列的可以得到长度为5的两个不相交的"转调后的重复子序列", 序列一:1 2 3 4 5(变化程度 1 1 1 1) 序列二:6 7 8 9 10(变化程度1 1 1 1) ,变化程度为相邻两个数字的差值。

所以我们可以利用变化序列,得到变化序列后我们就可以用上面的思路来求解了。 因为是通过变化序列来求解,所以答案序列是变化序列+1。

 

  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 = 2e6+6;
 16 
 17 int s[maxn];
 18 int sa[maxn],t[maxn],t2[maxn],c[maxn];
 19 int Rank[maxn],height[maxn];
 20 
 21 void build_sa(int n,int m)
 22 
 23     int i,j,*x=t,*y=t2;
 24     for (i=0;i<m;i++)
 25         c[i] = 0;
 26     for (i=0;i<n;i++)
 27         c[x[i] = s[i]]++;
 28     for (i=1;i<m;i++)
 29         c[i] += c[i-1];
 30     for (i=n-1;i>=0;i--)
 31         sa[--c[x[i]]] = i;
 32     for (int k=1;k<=n;k<<=1)
 33     
 34         int p = 0;
 35         for (i=n-k;i<n;i++)
 36             y[p++] = i;
 37         for (i=0;i<n;i++)
 38         
 39             if (sa[i]>=k)
 40                 y[p++] = sa[i]-k;
 41         
 42         for (i=0;i<m;i++)
 43             c[i] = 0;
 44         for (i=0;i<n;i++)
 45             c[x[y[i]]]++;
 46         for (i=1;i<m;i++)
 47             c[i] += c[i-1];
 48         for (i=n-1;i>=0;i--)
 49             sa[--c[x[y[i]]]] = y[i];
 50         swap(x,y);
 51         p = 1;
 52         x[sa[0]] = 0;
 53         for (i=1;i<n;i++)
 54             x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
 55         if (p>=n)
 56             break;
 57         m = p;
 58     
 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 int n;
 78 bool check(int k)
 79     int maxsa=sa[0],minsa=sa[0];
 80     for (int i=1;i<n;i++)
 81         if (height[i]>=k)
 82             minsa = min(sa[i],minsa);
 83             maxsa = max(sa[i],maxsa);
 84         
 85         else
 86             if (maxsa-minsa>=k)
 87                 return true;
 88             maxsa = sa[i];
 89             minsa = sa[i];
 90         
 91     
 92     if (maxsa-minsa>=k)
 93         return true;
 94     
 95     return false;
 96 
 97 
 98 int main()
 99     while (~scanf("%d",&n) && n!=0)
100         for (int i=0;i<n;i++)
101             scanf("%d",&s[i]);
102         
103         for (int i=0;i<n;i++)
104             if (i == n-1)
105                 s[i] = 0;
106             else
107                 s[i] = s[i+1]-s[i] + 100;
108         
109         build_sa(n,200);
110         getHeight(n-1);
111         int l=0,r=n,mid;
112         while (l<=r)
113             mid = (l+r)>>1;
114             if (check(mid))
115                 l = mid+1;
116             
117             else
118                 r = mid-1;
119             
120         
121         if (r<4)
122             printf("0\\n");
123         
124         else
125             printf("%d\\n",r+1);
126         
127     
128     return 0;
129 

 

以上是关于不可重叠最长重复子串的主要内容,如果未能解决你的问题,请参考以下文章

不可重叠最长重复子串

poj1743(不可重叠最长重复子串,二分+后缀数组)

hiho120 后缀数组一·重复旋律2字符串--后缀数组--最长不可重叠重复子串问题

POJ 1743 Musical Theme(后缀数组[不可重叠最长重复子串])

POJ 1743 Musical Theme(后缀数组[不可重叠最长重复子串])

POJ-1743 Musical Theme 字符串问题 不重叠最长重复子串