题目大意:
* 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。 * “主题”是整个音符序列的一个子串,它需要满足如下条件: * 1.长度至少为5个音符 * 2.在乐曲中重复出现(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值。) * 3.重复出现的同一主题不能有公共部分。
分析:也是看的论文才做的这道题,学了4天的后缀数组,终于A掉一道题了,啥也不说了,都是眼泪(怎么做可以看看论文,说的很详细)。
代码如下:
===============================================================================================================
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<algorithm> using namespace std; const int MAXN = 2e4+7; const int BaseNum = 90; struct SuffixArr { int text[MAXN], tempx[MAXN], tempy[MAXN]; int sum[MAXN], rank[MAXN], sa[MAXN], heigh[MAXN]; int *x, *y, N, MaxId; void Insert(int mus[], int len) { N = len, MaxId = 200; x = tempx, y=tempy; for(int i=0; i<N; i++) { x[i] = text[i] = mus[i]; y[i] = i; } } void BaseSort() { for(int i=0; i<MaxId; i++) sum[i] = 0; for(int i=0; i<N; i++) sum[ x[ y[i] ] ] += 1; for(int i=1; i<MaxId; i++) sum[i] += sum[i-1]; for(int i=N-1; i>=0; i--) sa[ --sum[ x[ y[i] ] ] ] = y[i]; } bool OK(int i, int len) { if(sa[i]+len>N || sa[i-1]+len>N) return false; if(y[sa[i]] != y[sa[i-1]] || y[sa[i]+len] != y[sa[i-1]+len]) return false; return true; } void Build_Sa() { BaseSort(); for(int len=1; len<N; len<<=1) { int id = 0; for(int i=N-len; i<N; i++) y[id++] = i; for(int i=0; i<N; i++)if(sa[i]>=len) y[id++] = sa[i] - len; BaseSort(); swap(x, y); x[ sa[0] ] = id = 0; for(int i=1; i<N; i++) { if(OK(i, len) == true) x[ sa[i] ] = id; else x[ sa[i] ] = ++id; } MaxId = id+1; if(MaxId >= N)break; } } void GetHeight() { for(int i=0; i<N; i++) rank[ sa[i] ] = i; for(int k=0,i=0; i<N; i++) { if(!rank[i]) { k = heigh[0] = 0; continue; } if(k)k--; int pre = sa[ rank[i]-1 ]; while(text[pre+k] == text[i+k]) k++; heigh[rank[i]] = k; } } }; struct SuffixArr suf; int music[MAXN]; bool Find(int k) { int Min, Max; Min = Max = suf.sa[0]; for(int i=1; i<suf.N; i++) { if(suf.heigh[i] < k) Min = Max = suf.sa[i]; else { Min = min(Min, suf.sa[i]); Max = max(Max, suf.sa[i]); if(Max-Min > k) return true; } } return false; } int main() { int i, N; while(scanf("%d", &N), N) { for(i=0; i<N; i++) { scanf("%d", &music[i]); if(i)music[i-1] = music[i-1]-music[i]+BaseNum; } music[N-1] = 0; suf.Insert(music, N); suf.Build_Sa(); suf.GetHeight(); int L=4, R=N/2, ans=-1; while(L <= R) { int Mid = (L+R)>>1; if(Find(Mid) == true) { L = Mid + 1; ans = Mid; } else R = Mid - 1; } printf("%d\n", ans+1); } return 0; }
时间: 2024-09-27 23:16:57