关闭

HDU 5558 后缀数组

标签: ACMhdu数据结构后缀数组
558人阅读 评论(0) 收藏 举报
分类:

点击打开链接

题意:从第一个字符开始,找到一个从0到当前位置i之前的与i开始的字符串的最长匹配长度及位置,长度相同时,要位置小的,若存在,位置+最长长度,否则+1

思路:15年合肥的现场题目,据说牌子发不完了,这道题的题目数据变弱后才可以将牌子发光,HDU的应该也是弱数据的版本,但是也不太好处理,看了大牛的思路才自己照着样子写了写,大牛的做法,其实我就是完全的按照神犇的做法写的,大家可以去看他的博客,思路就是对于当前的位置i,它的排名找出来,然后它的前边和后边是可能有与其有匹配情况的,也只有这个情况才能匹配,然后找这两部分就行,如果已经找到的长度是K,那么当下一个长度不够K时,跳出即可,这样看i与i+1的匹配长度为L,i+1与i+2的匹配长度为L1,那么i与i+2的匹配长度一定是两者取小的那个,所以再找到一个比K小的,后面都是比K小的,这样就降低了复杂度,但是还是不知道能不能过了现场的题目,然后先是预处理一下左右可到的区间,这都是在高度数组上进行的,然后跑一遍找就可以了,写到这发现其实不予处理也可以,因为那个小于K那个已经很优化了,刚刚测试一下,也过了,慢了一点而已

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int MAXN=1000010;
int wa[MAXN],wb[MAXN],wv[MAXN],ww[MAXN];
int sa[MAXN],lcp[MAXN],Rank[MAXN],rank1[MAXN],vis[MAXN];
char str[MAXN];
inline bool cmp(int *r,int a,int b,int len){
    return r[a]==r[b]&&r[a+len]==r[b+len];
}
 void construct_sa(int n,int m){
     int i,j,p,*x=wa,*y=wb,*t;n++;
     for(i=0;i<m;i++) ww[i]=0;
     for(i=0;i<n;i++) ww[x[i]=str[i]]++;
     for(i=1;i<m;i++) ww[i]+=ww[i-1];
     for(i=n-1;i>=0;i--) sa[--ww[x[i]]]=i;
     for(j=p=1;p<n;j<<=1,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<m;i++) ww[i]=0;
         for(i=0;i<n;i++) ww[wv[i]=x[y[i]]]++;
         for(i=1;i<m;i++) ww[i]+=ww[i-1];
         for(i=n-1;i>=0;i--) sa[--ww[wv[i]]]=y[i];
         for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)
             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
}
void construct_lcp(int n){
    for(int i=0;i<=n;i++) rank1[sa[i]]=i;
    int h=0;
    lcp[0]=0;
    for(int i=0;i<n;i++){
        int j=sa[rank1[i]-1];
        if(h>0) h--;
        for(;j+h<n&&i+h<n;h++) if(str[i+h]!=str[j+h]) break;
        lcp[rank1[i]-1]=h;
    }
}
int fa[MAXN],son[MAXN];
int main(){
    int T,cas=1;
    scanf("%d",&T);
    while(T--){
        scanf("%s",str);
        int len=strlen(str);
        memset(fa,0,sizeof(fa));
        memset(son,0,sizeof(son));
        construct_sa(len,300);sa[len+1]=inf;
        construct_lcp(len);
        for(int i=1;i<=len;i++){
            if(lcp[i-1]==0) fa[i]=i;
            else fa[i]=fa[i-1];
        }
        for(int i=len;i>0;i--){
            if(lcp[i]==0||i==len) son[i]=i;
            else son[i]=son[i+1];
        }
        printf("Case #%d:\n",cas++);
        for(int i=0;i<len;){
            if(i==0){
                printf("-1 %d\n",(int)str[i]);
                i++;continue;
            }
            int min1=0,pos=inf,fen=rank1[i];
            int max1;
            max1=lcp[fen];
            for(int j=fen;j<=son[fen];j++){
                max1=min(max1,lcp[j]);
                if(max1<min1) break;
                if(sa[j+1]>=i) continue;
                if(max1>min1){
                    min1=max1;pos=sa[j+1];
                }else if(max1==min1&&pos>sa[j+1]) pos=sa[j+1];
            }
            if(fen-1>=fa[fen]) max1=lcp[fen-1];
            for(int j=fen-1;j>=fa[fen];j--){
                max1=min(max1,lcp[j]);
                if(max1<min1) break;
                if(sa[j]>=i) continue;
                if(max1>min1){
                    min1=max1;pos=sa[j];
                }else if(max1==min1&&pos>sa[j]) pos=sa[j];
            }
            if(min1==0){
                printf("-1 %d\n",(int)str[i]);
                i++;
            }else{
                printf("%d %d\n",min1,pos);
                i+=min1;
            }
        }
    }
    return 0;
}

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:304420次
    • 积分:6083
    • 等级:
    • 排名:第4126名
    • 原创:318篇
    • 转载:0篇
    • 译文:0篇
    • 评论:10条
    友情链接
    博客专栏
    最新评论