【后缀数组】[POJ 1743]Musical Theme
题目分析
后缀数组模板题目,我们可以二分一下答案然后我们在构建的每两个数的差所求得的height数组中查找当前连续大于mid的一个区间的pos最小和pos最大值得差值,然后如果这个差值大于了mid我们才认为可以使用,否则会因为有一个节点重叠(相当于每一个差值表示的是一条边,如果刚好相等,那么这两个边的一对端点是重合的)
这里有几点要注意
- 后缀数组时最后一个循环要反着
- 后缀数组在判断rank的种类是否大于等于n时要在循环底部,不应在条件中否则有可能无法进入循环
- 注意统计数量的数组一定要和存放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;
}