• POJ-3294-Life Forms(后缀数组-不小于 k 个字符串中的最长子串)


    题意:

    给定 n 个字符串,求出现在不小于 k 个字符串中的最长子串。

    分析:

    将 n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组。

    然后二分答案,将后缀分成若干组,判断每组的后缀是否出现在不小于 k 个的原串中。

    如果是大于127, char 是负数, 在计数排序的时候是会出问题的。

    这题在输出上WA了很多次。最后下载了数据才找出来的。。。。

    // File Name: 3294.cpp
    // Author: Zlbing
    // Created Time: 2013年09月07日 星期六 16时21分37秒
    
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<cstring>
    #include<stack>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define CL(x,v); memset(x,v,sizeof(x));
    #define INF 0x3f3f3f3f
    #define LL long long
    #define REP(i,r,n) for(int i=r;i<=n;i++)
    #define RREP(i,n,r) for(int i=n;i>=r;i--)
    //rank从0开始
    //sa从1开始,因为最后一个字符(最小的)排在第0位
    //height从2开始,因为表示的是sa[i-1]和sa[i]
    const int MAXN=220000;
    int rank[MAXN],sa[MAXN],X[MAXN],Y[MAXN],height[MAXN];
    int s[MAXN];
    int buc[MAXN];
    int T[MAXN];
    void calheight(int n) {
        int i , j , k = 0;
        for(i = 1 ; i <= n ; i++) rank[sa[i]] = i;
        for(i = 0 ; i < n ; height[rank[i++]] = k)
            for(k?k--:0 , j = sa[rank[i]-1] ; s[i+k] == s[j+k] ; k++);
    }
    bool cmp(int *r,int a,int b,int l) {
        return (r[a] == r[b] && r[a+l] == r[b+l]);
    }
    void suffix(int n,int m = 128) {
        int i , l , p , *x = X , *y = Y;
        for(i = 0 ; i < m ; i ++) buc[i] = 0;
        for(i = 0 ; i < n ; i ++) buc[ x[i] = s[i]  ] ++;
        for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1];
        for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[i] ]] = i;
        for(l = 1,p = 1 ; p < n ; m = p , l *= 2) {
            p = 0;
            for(i = n-l ; i < n ; i ++) y[p++] = i;
            for(i = 0 ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l;
            for(i = 0 ; i < m ; i ++) buc[i] = 0;
            for(i = 0 ; i < n ; i ++) buc[ x[y[i]] ] ++;
            for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1];
            for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[y[i]] ] ] = y[i];
            for(swap(x,y) , x[sa[0]] = 0 , i = 1 , p = 1 ; i < n ; i ++)
                x[ sa[i] ] = cmp(y,sa[i-1],sa[i],l) ? p-1 : p++;
        }
        calheight(n-1);//后缀数组关键是求出height,所以求sa的时候顺便把rank和height求出来
    }
    int vis[1005];
    bool solve(int x,int k,int n)
    {
        CL(vis,0);
        vis[0]=1;
        int tot=0;
        if(!vis[T[sa[1]]])
            tot++;
        vis[T[sa[1]]]=1;
        for(int i=2;i<=n;i++)
        {
            if(height[i]<x)
            {
                tot=0;
                CL(vis,0);
                vis[0]=1;
                if(!vis[T[sa[i]]])
                    tot++;
                vis[T[sa[i]]]=1;
                continue;
            }
            if(!vis[T[sa[i]]])tot++;
            if(tot>=k)return true;
            vis[T[sa[i]]]=1;
        }
        return false;
    }
    void print(int x,int k,int n)
    {
        CL(vis,0);
        int tot=0;
        vis[0]=1;
        if(!vis[T[sa[0]]])
            tot++;
        vis[T[sa[0]]]=1;
        for(int i=1;i<=n;i++)
        {
            if(height[i]<x)
            {
                if(tot>=k)
                {
                    for(int j=0;j<x;j++)
                        printf("%c",s[sa[i-1]+j]-6);
                    printf("
    ");
                }
                tot=0;
                CL(vis,0);
                vis[0]=1;
                if(!vis[T[sa[i]]])
                    tot++;
                vis[T[sa[i]]]=1;
                continue;
            }
            if(!vis[T[sa[i]]])tot++;
            vis[T[sa[i]]]=1;
        }
        //这里一开始没写导致WA了很多次
        if(tot>=k)
        {
            for(int j=0;j<x;j++)
                printf("%c",s[sa[n]+j]-6);
            printf("
    ");
        }
    }
    int main() {
        //freopen("C.dat","r",stdin);
        //freopen("Cout.dat","w",stdout);
        int N;
        char ch[1105];
        int first=0;
        while(~scanf("%d",&N))
        {
            if(!N)break;
            if(first)printf("
    ");
            first++;
            int k=N/2+1;
            int n=0;
            int tt=1;
            int L=1,R=0;
            REP(i,1,N)
            {
                scanf("%s",ch);
                int len=strlen(ch);
                R=max(R,len);
                REP(j,0,len-1)
                {
                    s[n++]=(int)ch[j]+6;
                    T[n-1]=i;
                }
                s[n++]=tt++;
                T[n-1]=0;
            }
            //printf("case %d:",first);
            if(N==1)
            {
                printf("%s
    ",ch);
                continue;
            }
            s[n-1]=0;
            T[n-1]=0;
            n--;
            suffix(n+1,200);
            int ans=-1;
            while(L<=R)
            {
                int mid=L+(R-L+1)/2;
                if(solve(mid,k,n))
                {
                    ans=max(ans,mid);
                    L=mid+1;
                }
                else R=mid-1;
            }
            //printf("%d
    ",ans);
            if(ans!=-1)
            print(ans,k,n);
            else printf("?
    ");
        }
        return 0;
    }
  • 相关阅读:
    axios的数据请求方式及跨域
    vuex 的介绍
    返回顶部的过渡式写法
    数据结构和算法——二叉树
    RecyclerView的刷新和加载更多
    希尔排序小结
    选择排序小结
    插入排序小结
    冒泡、快速排序小结
    数据结构和算法——递归算法
  • 原文地址:https://www.cnblogs.com/arbitrary/p/3308744.html
Copyright © 2020-2023  润新知