HDU 5558 后缀数组

原创 2016年06月01日 17:01:40

点击打开链接

题意:从第一个字符开始,找到一个从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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 5558 Alice's Classified Message (后缀自动机水题) 2015年合肥区域赛G题

好久没写题解了唔..... 今天水了一题...写一下吧... 题目大意: 就是现在给出长度不超过10W的只包含小写字母的字符串,从下标0到 length - 1 现在从下标0开始进行操...

hdu5558 后缀数组

Alice's Classified Message Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K...

HDU 5558 2015ICPC合肥站G题

题意:给一个字符串加密,加密规则为: 对于第i个字符  如果存在S[T.....T+K-1] == S[i....i+K-1]     则输出T,K  如果有多种方法输出K最大的  如果有多种K最大...

HDU5558后缀自动机模板题

我只能说后缀自动机时间复杂度简直666     感叹clj神#include using namespace std; const int maxn=100005; const int SIGM...

HDU 5558 (后缀数组 二分 RMQ)

题目链接:点击这里求一个串每一个后缀和他最长匹配的他之前的后缀.题意: 给定一个串, 下标从0开始, 从这个下标之前的下标中找到一个最小下标使得这两个后缀的最长公共前缀最大, 设这个值为L. 如果存在...

[HDU 5558] Alice's Classified Message (后缀数组+LCP+单调栈)

链接HDU 5558题意题意较复杂,可看原题。 基本上等同于对一个字符串的若干个位置i求其前方位置j(0 ...

Hdu 5558 Alice's Classified Message(后缀数组,每个点的前面点和它匹配的最长长度)

传送门:Hdu 5558 Alice’s Classified Message题意:给你一个字符串(长度小于等于1e5),从起点为0出发,每次判断这个点和其前面的点的最长子串匹配,如果最长子串匹配长度...

[后缀自动机] HDU5558 Alice's Classified Message

Alice’s Classified Message题意:给一个串s,给一个加密过程,输出密文,过程如下: 初始i = 0,重复下面直到串结束。 找一个子串,第一个字符位于[0,i),而且该子串要...
  • kg20006
  • kg20006
  • 2016年09月11日 20:17
  • 290

HDU 5558

http://acm.split.hdu.edu.cn/showproblem.php?pid=5558题意: 给一个串,求出 串中以某个位置 i 开头的子串,在 i 之前 是否存在一个 T 使得 以...

hdu5558 Alice's Classified Message

Alice's Classified Message Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU 5558 后缀数组
举报原因:
原因补充:

(最多只允许输入30个字)