不可重叠最长重复子串
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
以上是关于不可重叠最长重复子串的主要内容,如果未能解决你的问题,请参考以下文章
hiho120 后缀数组一·重复旋律2字符串--后缀数组--最长不可重叠重复子串问题
POJ 1743 Musical Theme(后缀数组[不可重叠最长重复子串])