zoukankan      html  css  js  c++  java
  • HDU 5558 Alice's Classified Message(后缀数组+二分+rmq(+线段树?))

    题意

    大概就是给你一个串,对于每个(i),在([1,i-1])中找到一个(j),使得(lcp(i,j))最长,若有多个最大(j)选最小,求(j)和这个(lcp)长度

    思路

    首先我们需要知道对于每个(i),能与下标小于(i)开头的前缀构成的最大(lcp)是多少
    这个可以在最外层枚举(i)的过程中维护一个(set),这样在插入当前的(rk[i])的时候能(O(logn))得到这个最长的(lcp)

    然后根据这个值二分出(rk[i])向左右能扩展的最远的地方([L,R]),使得(lcp)依然为这个值
    ([L,R])内的最小的(sa)就是答案

    脑子抽了用了个线段树维护已经存在过的下标,没出现的用(inf)表示,但实际上无论是inf还是本身它都不可能是真正的答案,所以这边还是rmq
    不过复杂度不影响,少了点常数..

    代码

    下面注释提供了一些自己拍出来的数据
    谁让我不会自动机呢

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<stack>
    #include<queue>
    #include<deque>
    #include<set>
    #include<vector>
    #include<map>
    #include<functional>
        
    #define fst first
    #define sc second
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    #define lson l,mid,root<<1
    #define rson mid+1,r,root<<1|1
    #define lc root<<1
    #define rc root<<1|1
     
    using namespace std;
     
    typedef double db;
    typedef long double ldb;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> PI;
    typedef pair<ll,ll> PLL;
    typedef pair<ll,int> PIL;
     
    const db eps = 1e-6;
    const int mod = 1e9+7;
    const int maxn = 3e5+100;
    const int maxm = 2e6+100;
    const int inf = 0x3f3f3f3f;
    const db pi = acos(-1.0);
    
    
    int t;
    int n,m;
    char s[maxn];
    int sa[maxn],rk[maxn],height[maxn];
    int y[maxn],x[maxn],c[maxn];
    void getSa(){
        for(int i=1;i<=n;i++)++c[x[i]=s[i]];
        for(int i=2;i<=m;i++)c[i]+=c[i-1];
        for(int i=n;i>=1;i--){
            
            //printf("sa[%d]=%d
    ",c[x[i]],i);
            sa[c[x[i]]--]=i;
        }
        for(int k=1;k<=n;k<<=1){
            //printf("^^^^%d
    ",k);
            int num = 0;
            for(int i=n-k+1;i<=n;i++)y[++num]=i;
            for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
            
            for(int i=1;i<=m;i++)c[i]=0;
            for(int i=1;i<=n;i++)++c[x[i]];
            for(int i=2;i<=m;i++)c[i]+=c[i-1];
            for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
            swap(x,y);
            x[sa[1]]=1;
            num=1;
            for(int i = 1; i <= n; i++){
                //printf("y[%d]=%d
    ",i,y[i]);
            }
            for(int i=2;i<=n;i++){
                x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
                /*printf("num==%d
    ",num);
                printf("x[%d]=(y[%d]==y[%d]&&y[%d]==y[%d])?num:++num
    ",sa[i],sa[i],sa[i-1],sa[i]+k,sa[i-1]+k);*/
            }
            if(num==n)break;
            m=num;
        }
    }
    void getHeight(){
        int k=0;
        for(int i=1; i<=n; ++i)rk[sa[i]]=i;
        for(int i=1; i<=n; ++i){
            if(rk[i]==1) continue;
            if(k)--k;
            int j=sa[rk[i]-1];
            while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k])++k;
            height[rk[i]]=k;
        }
    }
    set<int>S;
    int d[maxn][23];
    void init(){
        for(int i = 1; i <= n; i++)d[i][0]=height[i];
            for(int j = 1; (1<<j)<=n; j++){
                for(int i = 1; i+(1<<j)-1<=n; i++){
                    d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
                }
            }
    }
    int rmq(int l, int r){
        if (l > r) swap (l, r);
        int k = 0;
        while((1<<(k+1))<=r-l+1)k++;
        return min(d[l][k],d[r-(1<<k)+1][k]);
    }
    int mi[maxn<<2];
    void build(int l, int r, int root){
        int mid = l+r>>1;
        if(l==r){mi[root]=inf;return;}
        build(lson);build(rson);
        mi[root]=min(mi[lc],mi[rc]);
        return;
    }
    void update(int x, int y, int l, int r, int root){
        int mid = l+r>>1;
        if(l==r){mi[root]=y;return;}
        if(x<=mid)update(x,y,lson);
        else update(x,y,rson);
        mi[root]=min(mi[lc],mi[rc]);
        return;
    }
    int ask(int x, int y, int l, int r, int root){
        int mid=l+r>>1;
        if(x<=l&&r<=y)return mi[root];
        int ans = inf;
        if(x<=mid)ans=min(ans,ask(x,y,lson));
        if(y>mid)ans=min(ans,ask(x,y,rson));
        return ans;
    }
    int ntot;
    PI Ans[maxn];
    int main(){
        scanf("%d", &t);
        int ncase = 0;
        while(t--){
            scanf("%s",s+1);
            n = strlen(s+1);
            m=122;
            for(int i = 0; i <= m; i++)c[i]=0;
            //for(int i = 0; i <= 2*n+2; i++)x[i]=y[i]=0;
    
            getSa();
            /*
            for(int i = 1; i <= n; i++){
                printf("  %d %d %d
    ",i,x[i],y[i]);
            }*/
            getHeight();
            printf("Case #%d:
    ",++ncase);
            S.clear();
            init();
            build(1,n,1);
            for(int i = 1; i <= n; ){
                int mxLen = 0;
                set<int>::iterator it = S.lower_bound(rk[i]);
                if(it!=S.end()){
                    mxLen=max(mxLen,rmq(rk[i]+1,(*it)));
                }
                
                if(it!=S.begin()){
                    it--;
                    mxLen=max(mxLen,rmq((*it)+1,rk[i]));
                }
                S.insert(rk[i]);
                if(!mxLen){
                    printf("-1 %d
    ",s[i]);
                    update(rk[i],i,1,n,1);
                    i++;
                    continue;
                }
                int L = -1,R=-1;
                int l=1,r=rk[i]-1;
                while(l<=r){
                    int mid=l+r>>1;
                    if(rmq(mid+1,rk[i])>=mxLen){
                        L=mid;r=mid-1;
                    }
                    else l=mid+1;
                }
                l=rk[i]+1,r=n;
                while(l<=r){
                    int mid=l+r>>1;
                    int tmp = rmq(rk[i]+1,mid);
                    if(rmq(rk[i]+1,mid)>=mxLen){
                        R=mid;l=mid+1;
                    }
                    else r=mid-1;
                }
                int to = i+mxLen;
                if(L==-1)L=inf;
                else L=ask(L,rk[i],1,n,1);
                if(R==-1)R=inf;
                else R=ask(rk[i],R,1,n,1);
                int ans=min(L,R);
                printf("%d %d
    ",mxLen,ans-1);
                
                while(i<to){
                    S.insert(rk[i]);
                    update(rk[i],i,1,n,1);
                    i++;
                    if(i>n)break;
                }
            }
        }
        return 0;
    }
    /*
    
    1
    zlikumoyyokhaokil
    
    stuiftqhxcksooesore
    
    txtvacgqjtvxheeq
    
    xnghnjzwjlpiyjlwf
    
    qjvxxmhhbhbqingby
    
    fsutshglayemjmshy
    
    fxoxaepodcfvxaisda
    
    
    44444
    sad
    a
    d
    sa
    
    2
    psdkfdsokfpslb
    svvvcxxxxaaaa
    
    1
    svvvcxxxxaaaa
    
    dsfwfqqqfqq
    svvvcxxxxaaaa
    
    2
    aaaaabbbbbaaabbc
    aaaaaa
    
    uiuiuiuiiuiui
    
    sad
    a
    d
    sa
    sdddqqdqqqerr
    psdkfdsokfpslbl
    svvvcxxxxaaaa
    dsfwfqqqfqq
    
    dsjdfssdjf
    sasasaosos
    
    doodfofsdoos
    osdosofifi
    soodfofofo
    asoidosgkoogo
    sifioobibninni
    sidibvhbjjj
    jjajjajjajajaj
    siisisiii
    iiiiiiii
    a
    sdiibibi
    vv
    sddddds
    
     */
    
  • 相关阅读:
    [转]ABAP动态取得数据
    [转]ABAP学习笔记之三内表
    [转]ABAP实现对变式的修改
    [转]ABAP Search help
    C#中访问私有成员[转载]
    如果在BackgroundWorker运行过程中关闭窗体…
    交叉编译的概念
    索引器的重载的一个例子
    自定义类实现IComparable接口
    ioctl函数
  • 原文地址:https://www.cnblogs.com/wrjlinkkkkkk/p/11721408.html
Copyright © 2011-2022 走看看