A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1…88, each representing a key on the piano. It is unfortunate but true that this representation of melodies ignores the notion of musical timing; but, this programming task is about notes and not timings.
Many composers structure their music around a repeating &qout;theme&qout;, which, being a subsequence of an entire melody, is a sequence of integers in our representation. A subsequence of a melody is a theme if it:
is at least five notes long
appears (potentially transposed – see below) again somewhere else in the piece of music
is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s)
Transposed means that a constant positive or negative value is added to every note value in the theme subsequence.
Given a melody, compute the length (number of notes) of the longest theme.
One second time limit for this problem’s solutions!
- 题意:给一段数,求最大相似子串长度,如果没有输出0。(相似子串定义:长度≥5且不重叠的每两个数值相差都相同的子串。例如:12345和45678,差值都是3.)
- 思路:先相邻的两个数值做差,二分子串的长度,然后遍历height数组。因为排名相邻的最相似,所以相似子串长度可以尽量最长。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e4+5, INF = 0x3f3f3f3f;
int str[maxn];
int _rank[maxn], sa[maxn], height[maxn], _temp[maxn], bucket[maxn], ary[maxn];
int n, m; //m是自己定的,其实就是字母字符所占ascii码最大值,即桶的个数
void GetSa()
{
for(int i = 0; i <= n; i++) _rank[i] = str[i];
for(int i = 0; i < m; i++) bucket[i] = 0;
for(int i = 0; i <= n; i++) bucket[_rank[i]]++;
for(int i = 1; i < m; i++) bucket[i] += bucket[i-1];
for(int i = n; i >= 0; i--) sa[--bucket[_rank[i]]] = i;
for(int _size = 1; _size <= n; _size <<= 1)
{
int num = 0;
for(int i = n-_size+1; i <= n; i++) _temp[num++] = i;
for(int i = 0; i <= n; i++) if(sa[i] >= _size) _temp[num++] = sa[i]-_size;
for(int i = 0; i < m; i++) bucket[i] = 0;
for(int i = 0; i <= n; i++) bucket[_rank[_temp[i]]]++;
for(int i = 1; i < m; i++) bucket[i] += bucket[i-1];
for(int i = n; i >= 0; i--) sa[--bucket[_rank[_temp[i]]]] = _temp[i];
swap(_rank, _temp);
_rank[sa[0]] = 0, num = 1;
for(int i = 1; i <= n; i++) _rank[sa[i]] = (_temp[sa[i-1]] == _temp[sa[i]] && _temp[sa[i-1]+_size] == _temp[sa[i]+_size]) ? num-1 : num++;
m = num;
}
}
void GetHeight()
{
int k = 0;
for(int i = 1; i <= n; i++) _rank[sa[i]] = i;
for(int i = 0; i < n; i++)
{
if(k) k--;
else k = 0;
int j = sa[_rank[i]-1];
while(str[i+k] == str[j+k]) k++;
height[_rank[i]] = k;
}
}
bool judge(int k, int n)
{
int maxx = -INF, minn = INF;
for(int i = 2; i <= n; i++)
{
if(height[i] >= k)
{
maxx = max(maxx, max(sa[i], sa[i-1]));
minn = min(minn, min(sa[i], sa[i-1]));
if(maxx-minn > k) return true;
}
else
{
maxx = -INF; minn = INF;
}
}
return false;
}
int main()
{
while(~scanf("%d", &n), n)
{
for(int i = 0; i < n; i++) scanf("%d", &str[i]);
m = 256, n--;
for(int i = 0; i < n; i++) str[i] = str[i+1]-str[i]+88;
str[n] = 0;
GetSa();
GetHeight();
int l = 0, r = n>>1, ans = 0;
while(l <= r)
{
int mid = (l+r)>>1;
if(judge(mid, n)) l = mid+1, ans = mid+1;
else r = mid-1;
}
if(ans >= 5) printf("%d\n", ans);
else printf("0\n");
}
return 0;
}