zoukankan      html  css  js  c++  java
  • poj 3518 Corporate Identity 后缀数组->多字符串最长相同连续子串

    题目链接

    题意:输入N(2 <= N <= 4000)个长度不超过200的字符串,输出字典序最小的最长公共连续子串;

    思路:将所有的字符串中间加上分隔符,注:分隔符只需要和输入的字符不同,且各自不同即可,没有必要是最小的字符;

    连接后缀数组求解出height之后二分长度,由于height是根据sa数组建立的,所以前面符合的就是字典序最小的,直接找到就停止即可;

    ps: 把之前的模板简化了下,A题才是关键;

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    using namespace std;
    #define MS0(a) memset(a,0,sizeof(a))
    typedef long long ll;
    const int MAXN = 1000005;
    int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],wv[MAXN];
    int cmp(int *r, int a, int b, int l){
        return r[a] == r[b] && r[a+l] == r[b+l];
    }
    void build_sa(int *r, int n, int m){          //  倍增算法 r为待匹配数组  n为总长度 m为字符范围
        int i, j, p, *x = t, *y = t2;
        for(i = 0; i < m; i ++) c[i] = 0;
        for(i = 0; i < n; i ++) c[x[i] = r[i]] ++;
        for(i = 1; i < m; i ++) c[i] += c[i-1];
        for(i = n-1; i >= 0; i --) sa[--c[x[i]]] = i;
        for(j = 1, 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 < n; i ++) wv[i] = x[y[i]];
            for(i = 0; i < m; i ++) c[i] = 0;
            for(i = 0; i < n; i ++) c[wv[i]] ++;
            for(i = 1; i < m; i ++) c[i] += c[i-1];
            for(i = n-1; i >= 0; i --) sa[--c[wv[i]]] = y[i];
            for(swap(x,y), p = 1, x[sa[0]] = 0, i = 1; i < n; i++){
                x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p++;
            }
        }
    }
    int rk[MAXN],height[MAXN];
    void getHeight(int *r,int n)
    {
        for(int i = 1;i <= n;i++) rk[sa[i]] = i; // rk[i]:后缀i在sa[]中的下标
        for(int i = 0,j,k = 0; i < n; height[rk[i++]] = k){
            for(k? k--:0 ,j = sa[rk[i] - 1];r[i+k] == r[j+k];k++);
        }
    }
    int d[MAXN],num[MAXN],vs[4444],T,len,tot;
    char tt[222];
    bool check(int L)
    {
        MS0(vs);
        int cnt = 0;
        for(int i = 2;i <= tot;i++){
            if(height[i] < L){
                MS0(vs);
                cnt = 0;
                continue;
            }
            if(!vs[d[sa[i]]]){
                vs[d[sa[i]]] = 1;cnt++;
            }
            if(!vs[d[sa[i-1]]]){
                vs[d[sa[i-1]]] = 1;cnt++;
            }
            if(cnt == T){ //对于同一个长度,我们只取第一次出现的符合条件的字符串;
                for(int j = 0; j<L; j++)
                        tt[j] = num[sa[i]+j];
                    tt[L] = '';
                return true;
            }
        }
        return false;
    }
    char str[222];
    int main()
    {
        while(scanf("%d",&T) == 1 && T){
            tot = 0;
            for(int i = 1;i <= T;i++){
                scanf("%s",str);
                len = strlen(str);
                for(int j = 0;j < len;j++)
                    num[tot] = str[j],d[tot++] = i;
                num[tot] = 'z'+i,d[tot++] = 'z'+i;// '#' + i竟然WA了
            }
            num[tot] = 0;//最后添加一个最小字符;
            build_sa(num,tot+1,5155);
            getHeight(num,tot);
            int ans = 0,l = 1,r = len,mid,id;
            while(l <= r){
                mid = l + r >> 1;
                if(check(mid)){ans = mid,l = mid + 1;}
                else r = mid - 1;
            }
            if(ans){
                printf("%s
    ",tt);
            }
            else puts("IDENTITY LOST");
        }
        return 0;
    }
  • 相关阅读:
    python基础——列表生成式
    python基础——迭代
    python基础——切片
    python基础——递归函数
    python基础——函数的参数
    python基础——使用dict和set
    python基础——使用list和tuple
    python基础——字符串和编码
    堆——神奇的优先队列(下)
    堆——神奇的优先队列(上)
  • 原文地址:https://www.cnblogs.com/hxer/p/5380271.html
Copyright © 2011-2022 走看看