SDOI2008 Sandy的卡片( 后缀数组 )

求出后缀数组, 然后二分答案, 对height数组分组检验答案. 时间复杂度O(|S| log|S|)

--------------------------------------------------------------------------------

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
const int maxn = 1009;
const int maxN = 1000009;
 
inline int read() {
char c = getchar();
for(; !isdigit(c); c = getchar());
int ret = 0;
for(; isdigit(c); c = getchar())
ret = ret * 10 + c - '0';
return ret;
}
 
bool vis[maxn];
int str[maxn][maxn], len[maxn], n, Top;
int S[maxN], Id[maxN], stk[maxN], N;
int cnt[maxN], Sa[maxN], Height[maxN], Rank[maxN];
 
void Build(int m) {
int *x = Height, *y = Rank;
for(int i = 0; i < m; i++) cnt[i] = 0;
for(int i = 0; i < N; i++) cnt[x[i] = S[i]]++;
for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
for(int i = N; i--; ) Sa[--cnt[x[i]]] = i;
for(int k = 1, p = 0; k <= N; k <<= 1, 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++) cnt[i] = 0;
for(int i = 0; i < N; i++) cnt[x[y[i]]]++;
for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
for(int i = N; i--; ) Sa[--cnt[x[y[i]]]] = y[i];
swap(x, y);
p = 1;
x[Sa[0]] = 0;
for(int i = 1; i < N; i++) {
if(y[Sa[i]] != y[Sa[i - 1]] || y[Sa[i] + k] != y[Sa[i - 1] + k]) p++;
x[Sa[i]] = p - 1;
}
if(p >= N) break;
m = p;
}
for(int i = 0; i < N; i++) Rank[Sa[i]] = i;
Height[0] = 0;
for(int i = 0, h = 0; i < N; i++) if(Rank[i]) {
if(h) h--;
while(S[i + h] == S[Sa[Rank[i] - 1] + h]) h++;
Height[Rank[i]] = h;
}
}
 
void Init() {
int mn = 1 << 30, mx = -1 << 30;
n = read();
for(int i = 0; i < n; i++) {
len[i] = read();
for(int j = 0; j < len[i]; j++) str[i][j] = read();
for(int j = len[i]; --j; ) {
str[i][j] -= str[i][j - 1];
mn = min(mn, str[i][j]);
mx = max(mx, str[i][j]);
}
}
N = 0;
for(int i = 0; i < n; i++) {
for(int j = 1; j < len[i]; j++) {
S[N] = str[i][j] - mn + n;
Id[N++] = i;
}
S[N] = n - i - 1;
Id[N++] = n;
}
Build(mx - mn + n + 1);
memset(vis, 0, sizeof vis);
vis[n] = 1;
Top = 0;
}
 
bool chk(int v) {
while(Top) vis[stk[--Top]] = 0;
for(int i = 1; i < N; i++) if(Height[i] >= v) {
if(!vis[Id[Sa[i - 1]]])
vis[stk[Top++] = Id[Sa[i - 1]]] = 1;
if(!vis[Id[Sa[i]]])
vis[stk[Top++] = Id[Sa[i]]] = 1;
if(Top >= n) return true;
} else {
while(Top) vis[stk[--Top]] = 0;
}
return false;
}
 
void Work() {
int l = 1, r = maxN, ans = 0;
while(l <= r) {
int m = (l + r) >> 1;
if(chk(m)) {
ans = m, l = m + 1;
}
else
r = m - 1;
}
printf("%d\n", ++ans);
}
 
int main() {
Init();
Work();
return 0;
}

-------------------------------------------------------------------------------- 

posted @ 2016-01-16 20:42  JSZX11556  阅读(287)  评论(0编辑  收藏  举报