zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    eclipse下c/cpp " undefined reference to " or "launch failed binary not found"问题
    blockdev 设置文件预读大小
    宝宝语录
    CentOS修改主机名(hostname)
    subprocess报No such file or directory
    用ldap方式访问AD域的的错误解释
    英特尔的VTd技术是什么?
    This virtual machine requires the VMware keyboard support driver which is not installed
    Linux内核的文件预读详细详解
    UNP总结 Chapter 26~29 线程、IP选项、原始套接字、数据链路访问
  • 原文地址:https://www.cnblogs.com/arbitrary/p/3308744.html
Copyright © 2011-2022 走看看