您的位置:首页 > 其它

HDU 5558 后缀数组+二分

2015-11-24 23:16 183 查看
题意有一些绕,但其实就是对于不断变化的i,求以j(0=j<i)使得suffix[j]与suffix[i]的最长公共前缀最长,如果有多个j,则取最小的j。

可以在rank数组中二分,在1-rank[i-1]中二分最接近i的j使得sa[j]小于i,通俗地说就是rank比的rank[i]小,并且位于i之前的后缀。因为这个是左边最接近rank[i]的,所以与suffix[i]的最长公共前缀一定是满足最大的。接下来再根据得到的LCP值,二分一个最小的j。同理,再从rank[i+1]到rank
中作类似二分。两者结合得到当前的K和T。

其实这道题中间过程也可以不用二分,直接向左右暴力扫。速度会快很多。

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <string.h>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <cassert>
#include <sstream>
using namespace std;

const int N=1e5+10;

int MIN(int a,int b) {
return a<b?a:b;
}
int MAX(int a,int b) {
return a>b?a:b;
}

int val
;
struct RMQ {
int dp
[22];
int (*cmp) (int,int);
void setMin() {
cmp=MIN;
}
void setMax() {
cmp=MAX;
}
void init(int n,int *val) {
for (int i=0; i<=n; i++)
dp[i][0]=val[i];
for (int j=1; (1<<j)<=n; j++) {
int k=1<<(j-1);
for (int i=0; i+k<=n; i++)
dp[i][j]=cmp(dp[i][j-1],dp[i+k][j-1]);
}
}
int query(int a,int b) {
if (a>b) swap(a,b);
int dis=b-a+1;
int k=log((double)dis)/log(2.0);
return cmp(dp[a][k],dp[b-(1<<k)+1][k]);
}
} rmq;

char s
;
struct SuffixArray {
int wa
, wb
, cnt
, wv
;
int rk
, height
;
int sa
;
bool cmp(int r[], int a, int b, int l) {
return r[a] == r[b] && r[a+l] == r[b+l];
}
void calcSA(char r[], int n, int m) {
int i, j, p, *x = wa, *y = wb;
for (i = 0; i < m; ++i) cnt[i] = 0;
for (i = 0; i < n; ++i) cnt[x[i]=r[i]]++;
for (i = 1; i < m; ++i) cnt[i] += cnt[i-1];
for (i = n-1; i >= 0; --i) sa[--cnt[x[i]]] = i;
for (j = 1, p = 1; p < n; j *= 2, m = p) {
for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = 0; i < n; ++i) wv[i] = x[y[i]];
for (i = 0; i < m; ++i) cnt[i] = 0;
for (i = 0; i < n; ++i) cnt[wv[i]]++;
for (i = 1; i < m; ++i) cnt[i] += cnt[i-1];
for (i = n-1; i >= 0; --i) sa[--cnt[wv[i]]] = y[i];
for (swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
}
}
void calcHeight(char r[], int n) {
int i, j, k = 0;
for (i = 1; i <= n; ++i) rk[sa[i]] = i;
for (i = 0; i < n; height[rk[i++]] = k)
for (k?k--:0, j = sa[rk[i]-1]; r[i+k] == r[j+k]; k++);
}
int lcp(int a,int b,int len) {
if (a==b) return len-a;
int ra=rk[a],rb=rk[b];
if (ra>rb) swap(ra,rb);
return queryST(ra+1,rb);
}
int st
[22];
int preLog2
;
void initST(int n) {
for (int i=1; i<=n; i++)
st[i][0]=height[i];
for (int j=1; (1<<j)<=n; j++) {
int k=1<<(j-1);
for (int i=1; i+k<=n; i++)
st[i][j]=min(st[i][j-1],st[i+k][j-1]);
}
preLog2[1]=0;
for(int i=2;i<=n;i++){
preLog2[i]=preLog2[i-1]+((i&(i-1))==0);
}
}
int queryST(int a,int b) {
if (a>b) swap(a,b);
int dis=b-a+1;
int k=preLog2[dis];
return min(st[a][k],st[b-(1<<k)+1][k]);
}
void solve(int n) {
calcSA(s,n+1,128);
calcHeight(s,n);
initST(n);
rmq.setMin();
rmq.init(n,sa);
printf("-1 %d\n",s[0]);
int i=1;
while (i<n) {
int l=1,r=rk[i]-1;
int k=-1,t=s[i];
int minIndex=-1;
while (l<=r) {
int mid=(l+r)>>1;
int minSA=rmq.query(mid,rk[i]-1);
if (minSA<i)
l=mid+1,minIndex=minSA;
else
r=mid-1;
}
if (minIndex!=-1) {
int u=lcp(minIndex,i,n);
if (u) {
k=u;
int l=1,r=rk[i]-1,ret=-1;
while (l<=r) {
int mid=(l+r)>>1;
int curLCP=lcp(sa[mid],i,n);
if (curLCP>=u)
r=mid-1,ret=mid;
else l=mid+1;
}
t=rmq.query(ret,rk[i]-1);
}
}
l=rk[i]+1;
r=n;
minIndex=-1;
while (l<=r) {
int mid=(l+r)>>1;
int minSA=rmq.query(rk[i]+1,mid);
if (minSA<i)
r=mid-1,minIndex=minSA;
else
l=mid+1;
}
if (minIndex!=-1) {
int u=lcp(minIndex,i,n);
if (u&&u>=k) {
if (u==k)
t=min(t,minIndex);
else
t=minIndex;
k=u;
int l=rk[i]+1,r=n,ret=-1;
while (l<=r) {
int mid=(l+r)>>1;
int curLCP=lcp(sa[mid],i,n);
if (curLCP>=u)
l=mid+1,ret=mid;
else r=mid-1;
}
t=min(t,rmq.query(rk[i]+1,ret));
}
}
if (k==-1) {
printf("-1 %d\n",s[i]);
i++;
} else {
printf("%d %d\n",k,t);
i+=k;
}
}
}
} suf;

int main () {
int T;
scanf("%d",&T);
while (T--) {
scanf("%s",s);
int n=strlen(s);
static int cas=1;
printf("Case #%d:\n",cas++);
suf.solve(n);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: