1. 程式人生 > >【字尾陣列】[POJ 1743]Musical Theme

【字尾陣列】[POJ 1743]Musical Theme

題目分析

字尾陣列模板題目,我們可以二分一下答案然後我們在構建的每兩個數的差所求得的height陣列中查詢當前連續大於mid的一個區間的pos最小和pos最大值得差值,然後如果這個差值大於了mid我們才認為可以使用,否則會因為有一個節點重疊(相當於每一個差值表示的是一條邊,如果剛好相等,那麼這兩個邊的一對端點是重合的)

這裡有幾點要注意

  1. 字尾陣列時最後一個迴圈要反著
  2. 字尾陣列在判斷rank的種類是否大於等於n時要在迴圈底部,不應在條件中否則有可能無法進入迴圈
  3. 注意統計數量的陣列一定要和存放n的陣列大小相同

程式碼

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const
int MAXN = 500000; int sa[MAXN+10], r1[MAXN+10], r2[MAXN+10], counter[MAXN+10], height[MAXN+10]; void buildsa(int *s, int len, int kind){ for(int i=0;i<=kind;i++) counter[i] = 0; for(int i=1;i<=len;i++) counter[r1[i]=s[i]]++; for(int i=0;i<=kind;i++) counter[i] += counter[i-1]; for(int i=len
;i>=1;i--) sa[counter[r1[i]]--] = i; for(int i=1;i<len;i<<=1){ int p = 0; for(int j=len-i+1; j<=len; j++) r2[++p] = j; for(int j=1;j<=len;j++) if(sa[j] > i) r2[++p] = sa[j] - i; for(int j=0;j<=kind;j++) counter[j] = 0
; for(int j=1;j<=len;j++) counter[r1[r2[j]]]++; for(int j=0;j<=kind;j++) counter[j] += counter[j-1]; for(int j=len;j>=1;j--) sa[counter[r1[r2[j]]] --] = r2[j]; swap(r1, r2); r1[sa[1]] = kind = 1; for(int j=2;j<=len;j++) r1[sa[j]] = (r2[sa[j]] == r2[sa[j-1]] && r2[sa[j]+i] == r2[sa[j-1]+i]) ? kind : ++kind; if(kind >= len) break; } int now = 0; for(int i=1;i<=len;i++){ if(r1[i] == 1){ height[r1[i]] = now = 0; }else{ now = max(now-1, 0); int j = sa[r1[i]-1]; while(s[i+now] == s[j+now]) now++; height[r1[i]] = now; } } } bool check(int L, int n){ int Minpos = sa[1], Maxpos = sa[1]; for(int i=2;i<n;i++){ if(height[i] >= L){ Minpos = min(Minpos, sa[i]); Maxpos = max(Maxpos, sa[i]); }else{ if(Maxpos - Minpos > L) return true; Minpos = Maxpos = sa[i]; } } return Maxpos - Minpos > L; } int s[MAXN+10]; int main(){ int n; while(scanf("%d", &n), n){ for(int i=1;i<=n;i++) scanf("%d", &s[i]); for(int i=2;i<=n;i++) s[i-1] = s[i] - s[i-1] + 100; s[n] = 0; buildsa(s, n-1, 300); int l = 0, r = n-1, ans=0; while(l <= r){ int mid = (l + r) >> 1; if(check(mid, n-1)){ ans = mid; l = mid+1; }else r = mid-1; } if(ans < 4) printf("%d\n", 0); else printf("%d\n", ans+1); } return 0; }