• POJ 3294 出现在至少K个字符串中的子串


    在掌握POJ 2774(两个串求最长公共子串)以及对Height数组分组后,本题还是容易想出思路的。

    首先用字符集外的不同字符连接所有串,这是为了防止两个后缀在比较时超过某个字符串的分界。二分子串的长度,扫描height数组,判定是否有某个分组来源与至少K个原字符串(本题要求出现超过n的一半次)。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <string>
    #include <string.h>
    #include <stdio.h>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <cmath>
    #include <ctime>
    #include <cassert>
    #include <sstream>
    using namespace std;
    
    const int N=2e6+110;
    
    int sa[N];
    int t1[N],t2[N],c[N];
    int rk[N],height[N];
    
    inline int cmp(int *r,int a,int b,int l){
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    char s[N];
    void calcSA (char *s,int n,int m) {
        int i,j,p,*x=t1,*y=t2;
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[i]=s[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;j<=n;j<<=1){
            p=0;
            for(i=n-j;i<n;i++)y[p++]=i;
            for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
            for(i=0;i<m;i++)c[i]=0;
            for(i=0;i<n;i++)c[x[y[i]]]++;
            for(i=1;i<m;i++)c[i]+=c[i-1];
            for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
            swap(x,y);
            p=1;x[sa[0]]=0;
            for(i=1;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
            if(p>=n)break;
            m=p;
        }
    }
    
    void calcHeight(char *s,int n) {
        int i,j,k=0;
        for(i=0;i<=n;i++)rk[sa[i]]=i;
        for(i=0;i<n;i++){
            if(k)k--; // h[i]>=h[i-1]-1
            j=sa[rk[i]-1]; // suffix(j)排名在suffix(i)前一位
            while(s[i+k]==s[j+k])k++; // 暴力计算lcp
            height[rk[i]]=k;
        }
    }
    
    int belong[N];
    
    vector<int>ans;
    bool vis[128];
    bool ok(int n,int m,int k) {
        memset(vis,0,sizeof vis);
        int cnt=1;
        vis[belong[sa[1]]]=true;
        vector<int>ret;
        bool push=false;
        for (int i=2;i<=n;i++) {
            if (height[i]<m) {
                memset(vis,0,sizeof vis);
                push=false;
                vis[belong[sa[i]]]=true;
                cnt=1;
            }
            else if (!push){
                if (!vis[belong[sa[i]]]) {
                    vis[belong[sa[i]]]=true;
                    ++cnt;
                }
                if (cnt>k/2&&!push) {
                    push=true;
                    ret.push_back(sa[i]);
                }
            }
        }
        //cout<<"go "<<m<<" "<<ret.size()<<endl;
        if (ret.size()>0) {
            ans=ret;
            return true;
        }
        else return false;
    }
    int main () {
        int n;
        while (scanf("%d",&n)!=EOF,n) {
            int p=0;
            int maxLen=0;
            for (int i=1;i<=n;i++) {
                scanf("%s",s+p);
                int l=strlen(s+p);
                maxLen=max(maxLen,l);
                int np=p+l;
                for (int j=p;j<np;j++) {
                    belong[j]=i;
                    s[j]+=5; // 这里+5是为了保证插入的分隔符不在字符集中出现,n至多为100,a的ASCII为97
                }
                belong[np]=111;
                p=np;
                s[p++]=i;
            }
            s[--p]=0;
            belong[p]=-1;
            calcSA(s,p+1,550);
            calcHeight(s,p);
            int l=0,r=maxLen,ret=0;
            while (l<=r) {
                int m=(l+r)>>1;
                if (ok(p,m,n)) {
                    ret=m;
                    l=m+1;
                }
                else
                    r=m-1;
            }
            if (ret==0) {
                puts("?
    ");
            }
            else {
                for (int i=0;i<ans.size();i++) {
                    int beg=ans[i];
                    for (int j=0;j<ret;j++) printf("%c",s[beg+j]-5);
                    puts("");
                }
                puts("");
            }
        }
        return 0;
    }
  • 相关阅读:
    离奇的软件开发之路
    集群环境中的单例设计模式
    Android 如何更换屏幕上锁界面背景图片
    基于华为Java编程规范的Eclipse checkStyle.xml
    对数据库事务的总结
    [Sciter系列] MFC下的Sciter–1.创建工程框架
    Android 如何添加一种锁屏方式
    Hibernate级联操作 注解
    linux就是这个范儿之融于心而表于行(1)
    Android 如何修改默认的searchable items。
  • 原文地址:https://www.cnblogs.com/micrari/p/4820431.html
Copyright © 2020-2023  润新知