POJ-1743 Musical Theme 字尾陣列求不可重疊最長重複子串
阿新 • • 發佈:2020-11-29
POJ-1743 Musical Theme 字尾陣列求不可重疊最長重複子串
題意
給出一段樂曲,計算其中最長“主題”的長度
主題需要滿足
- 長度至少為5個字元
- 在樂曲中重複出現(可能經過轉調)
- 重複出現的同一主題不能有公共部分
所謂“轉調”,是指每個音符都被加上或者減去同個值。
樂曲中的每個音符都是1到88的整數
給出N,表示這段樂曲有N個音符,後給出整數
\[1\leq n\leq 20000 \]分析
首先轉調,可以轉化為差分做,再把整個樂曲看成一個字串,問題就變成了字串中不可重疊的最長重複子串,這個問題在羅老師的經典論文中已經詳細說明,這裡說幾個注意點
- 需要特判1
- 處理這類問題通常用int代替char
- 用劉汝佳老師的模板,通常需要加入一個'$',若是int,則是0
- 將問題轉化為判定性問題,分組 是處理字尾陣列問題的常用手段
程式碼
int s[maxn],p[maxn]; int sa[maxn],t[maxn],t2[maxn],c[maxn],n; void build_sa(int m){ int *x = t,*y = t2; for(int i = 0;i < m;i++) c[i] = 0; for(int i = 0;i < n;i++) c[x[i] = s[i]]++; for(int i = 1;i < m;i++) c[i] += c[i -1]; for(int i = n - 1;i >= 0;i--) sa[--c[x[i]]] = i; for(int k = 1;k <= n;k <<= 1){ int p = 0; for(int i = n - k;i < n;i++) y[p++] = i; for(int i = 0;i < n;i++) if(sa[i] >= k) y[p++] = sa[i] - k; for(int i = 0;i < m;i++) c[i] = 0; for(int i = 0;i < n;i++) c[x[y[i]]]++; for(int i = 0;i < m;i++) c[i] += c[i - 1]; for(int i = n - 1;i >= 0;i--) sa[--c[x[y[i]]]] = y[i]; swap(x,y); p = 1; x[sa[0]] = 0; for(int i = 1;i < n;i++) x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1:p++; if(p >= n) break; m = p; } } int rak[maxn],height[maxn]; void getHeight(){ int k = 0; for(int i = 0;i < n;i++) rak[sa[i]] = i; for(int i = 0;i < n;i++){ if(k) k--; int j = sa[rak[i] - 1]; while(s[i + k] == s[j + k]) k++; height[rak[i]] = k; } } bool check(int len){ int mx = sa[0],mi = sa[0]; for(int i = 1;i < n;i++){ if(height[i] >= len - 1) mx = max(sa[i],mx),mi = min(sa[i],mi); else mx = mi = sa[i]; if(mx - mi >= len) return true; } return false; } int solve(){ int l = 0,r = n,ans = 0; while(l <= r) { int mid = l + r >> 1; if(check(mid)) l = mid + 1,ans = mid; else r = mid - 1; } return ans; } int main(){ while(~scanf("%d",&n) && n){ for(int i = 0;i < n;i++) p[i] = readint(); if(n == 1) { puts("0"); continue; } for(int i = 0;i < n - 1;i++) s[i] = p[i + 1] - p[i] + 100; s[n - 1] = 0; build_sa(200); getHeight(); int ans = solve(); if(ans >= 5) printf("%d\n",ans); else puts("0"); } }