Musical Theme
题意:求一段旋律的最长主旋律(不可重叠)。
对给出的旋律做差,求后缀数组。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=20010; 7 const int inf=0x3f3f3f3f; 8 int s[maxn]; 9 int sa[maxn], t1[maxn],t2[maxn],c[maxn]; 10 int h[maxn],rank[maxn]; 11 int n; 12 void build_sa(int n, int m){ 13 int i, *x = t1, *y = t2; 14 for(i = 0; i < m; i++) c[i] = 0; 15 for(i = 0; i < n; i++) c[x[i] = s[i]]++; 16 for(i = 1; i < m; i++) c[i] += c[i-1]; 17 for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i; 18 19 for(int k = 1; k <= n; k <<= 1){ 20 int p = 0; 21 for(i = n-k; i < n; i++) y[p++] = i; 22 for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k; 23 for(i = 0; i < m; i++) c[i] = 0; 24 for(i = 0; i < n; i++) c[x[y[i]]]++; 25 for(i = 1; i< m; i++) c[i] += c[i-1]; 26 for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; 27 swap(x,y); 28 p = 1; 29 x[sa[0]] = 0; 30 for(i = 1; i < n; i++) 31 x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]? p-1 : p++; 32 if(p>=n) break; 33 m=p; 34 } 35 } 36 37 void geth(int n){ 38 int i, j, k=0; 39 for(i = 0; i <= n; i++) rank[sa[i]]=i; 40 for(i = 0; i < n; i++) { 41 if(k) k--; 42 j = sa[rank[i]-1]; 43 while(s[i+k]==s[j+k]) k++; 44 h[rank[i]] = k; 45 } 46 } 47 int ck(int k){ 48 int minn, maxn; 49 minn=maxn=sa[1]; 50 for(int i = 2; i <= n; i++) { 51 if(h[i] >= k){ 52 minn = min(minn, sa[i]); 53 maxn = max(maxn, sa[i]); 54 if(maxn-minn >= k) return 1; 55 }else { 56 maxn=minn=sa[i]; 57 } 58 } 59 return 0; 60 } 61 int main(){ 62 while(scanf("%d",&n)&&n){ 63 for(int i = 0; i < n; i++) scanf("%d",&s[i]); 64 for(int i = 0; i < n-1; i++) s[i] = s[i+1]-s[i]+88; 65 s[--n]=0; 66 build_sa(n+1,200); 67 geth(n); 68 int ans=0; 69 int l=4, r=n; 70 while(l <= r) { 71 int m=(l+r)>>1; 72 if(ck(m)) { 73 ans = m; 74 l = m+1; 75 } else { 76 r = m-1; 77 } 78 } 79 ans++; 80 printf("%d ",ans<5? 0:ans); 81 } 82 83 }