FZU problem 1985 LCP Problem

来源:互联网 发布:疯狂java讲义 豆瓣 编辑:程序博客网 时间:2024/05/28 05:15
给定n个字符串,询问任意两个字符串的最长公共前缀。每组数据最多100000个字符串,总长最多100000,询问最多100000。
解法一:hash+二分,二分最长公共前缀长度,用hash判定两个前缀是否一致。时间复杂度O(q*log(len))。
/*-------------------FZU 1985 by Temle----------------*/#include <iostream>#include <cstring>#include <cmath>#include <cstdio>#include <algorithm>#include <set>#include <map>#include <stack>#include <queue>#include <vector>#define ls(x) ((x)<<1)#define rs(x) ((x)<<1|1)using namespace std;typedef long long ll;typedef pair<ll,ll> pll;typedef pair<int,int> pii;#define mp(x,y) make_pair(x,y)#define fi first#define se second#define M 1000000007#define pri 233int hash1[201000],powh[201000];int getHash(int l,int r){    return hash1[r]-hash1[l-1]*powh[r-l+1];}char st[201000];int l[201000],r[201000];int main(){    powh[0]=1;    for (int i=1;i<201000;i++)        powh[i]=powh[i-1]*pri;    int T,ca;    for (scanf("%d",&T),ca=1;ca<=T;ca++)    {        int n;        scanf("%d",&n);        r[0]=0;        for (int i=1;i<=n;i++)        {            l[i]=r[i-1]+2;            scanf(" %s",st+l[i]);            r[i]=l[i]+strlen(st+l[i])-1;            hash1[l[i]-1]=0;            for (int j=l[i];j<=r[i];j++)                hash1[j]=hash1[j-1]*pri+st[j];        }        int m;        int x,y;        scanf("%d",&m);        printf("Case %d:\n",ca);        for (int i=1;i<=m;i++)        {            scanf("%d%d",&x,&y);            x++;y++;            int ans=0,l1,r1,mid;            l1=1;            r1=min(r[x]-l[x],r[y]-l[y])+2;            while (l1<r1)            {                mid=l1+r1>>1;                if (getHash(l[x],l[x]+mid-1)==getHash(l[y],l[y]+mid-1))                {                    ans=mid;                    l1=mid+1;                }else r1=mid;            }            printf("%d\n",ans);        }    }    return 0;}

解法二:使用字典树存取每种字符串,并记录每种字符串对应的字典树中的叶子位置,查询任意两个字符串的最长公共前缀相当于在字典树上跑LCA。时间复杂度O(q*log(len))。
/*-------------------FZU 1985 by Temle----------------*/#include <iostream>#include <cstring>#include <cmath>#include <cstdio>#include <algorithm>#include <set>#include <map>#include <stack>#include <queue>#include <vector>#define ls(x) ((x)<<1)#define rs(x) ((x)<<1|1)using namespace std;typedef long long ll;typedef pair<ll,ll> pll;typedef pair<int,int> pii;#define mp(x,y) make_pair(x,y)#define fi first#define se second#define M 1000000007int loc[101000],dep[101000],fa[101000][20];int trans[128];struct Trie{int tot;struct node{int next[4];} a[101000];void reset(int id){    memset(a[id].next,0,sizeof(a[id].next));}void init(){memset(fa,0,sizeof(fa));tot=0;reset(0);}void insert(char *st,int id){int root=0;for (int i=0;st[i];i++){int y=trans[st[i]];if (a[root].next[y]==0)  a[root].next[y]=++tot,reset(tot);root=a[root].next[y];}loc[id]=root;}void dfs(int x,int f){fa[x][0]=f;dep[x]=dep[f]+(x!=0);for (int i=0;i<4;i++)  if (a[x].next[i])    dfs(a[x].next[i],x);}void build(){for (int j=1;j<20;j++)  for (int i=1;i<=tot;i++)    fa[i][j]=fa[fa[i][j-1]][j-1];}int lca(int u,int v){if (dep[u]<dep[v]) swap(u,v);int dx=dep[u]-dep[v],tmp=0;while (dx){if (dx&1) u=fa[u][tmp];tmp++;dx>>=1;}for (int i=19;i>-1;i--){if (fa[u][i]!=fa[v][i])  u=fa[u][i],v=fa[v][i];}return u==v?u:fa[u][0];}} trie;char str[101000];int main(){trans['A']=0;trans['G']=1;trans['C']=2;trans['T']=3;int T,ca;for (scanf("%d",&T),ca=1;ca<=T;ca++){trie.init();int n;scanf("%d",&n);for (int i=0;i<n;i++){scanf(" %s",str);trie.insert(str,i);}trie.dfs(0,0);trie.build();int m;scanf("%d",&m);printf("Case %d:\n",ca);for (int i=0;i<m;i++){int x,y;scanf("%d%d",&x,&y);printf("%d\n",dep[trie.lca(loc[x],loc[y])]);}}    return 0;}


解法三:把所有字符串连接起来,中间用特殊字符分割,跑一遍后缀数组,然后只要计算任意两个后缀rank之间H数组的最小值即为答案。时间复杂度O(q*log(len))。
/*-------------------FZU 1985 by Temle----------------*/#include <iostream>#include <cstring>#include <cmath>#include <cstdio>#include <algorithm>#include <set>#include <map>#include <stack>#include <queue>#include <vector>#define ls(x) ((x)<<1)#define rs(x) ((x)<<1|1)using namespace std;typedef long long ll;typedef pair<ll,ll> pll;typedef pair<int,int> pii;#define mp(x,y) make_pair(x,y)#define fi first#define se second#define M 1000000007const int N=201000;int n,rank[N],sa[N],height[N],tmp[N],cnt[N];int s[N];void suffixarray(int n,int m){    int i,j,k;    n++;    for(i=0; i<n*2+5; i++)rank[i]=sa[i]=height[i]=tmp[i]=0;    for(i=0; i<m; i++)cnt[i]=0;    for(i=0; i<n; i++)cnt[rank[i]=s[i]]++;    for(i=1; i<m; i++)cnt[i]+=cnt[i-1];    for(i=0; i<n; i++)sa[--cnt[rank[i]]]=i;    for(k=1; k<=n; k<<=1)    {        for(i=0; i<n; i++)        {            j=sa[i]-k;            if(j<0)j+=n;            tmp[cnt[rank[j]]++]=j;        }        sa[tmp[cnt[0]=0]]=j=0;        for(i=1; i<n; i++)        {            if(rank[tmp[i]]!=rank[tmp[i-1]]||rank[tmp[i]+k]!=rank[tmp[i-1]+k])cnt[++j]=i;            sa[tmp[i]]=j;        }        memcpy(rank,sa,n*sizeof(int));        memcpy(sa,tmp,n*sizeof(int));        if(j>=n-1)break;    }    for(j=rank[height[i=k=0]=0]; i<n-1; i++,k++)        while(~k&&s[i]!=s[sa[j-1]+k])height[j]=k--,j=rank[sa[j]+1];}void get_height(int s[], int n){    int i, j, k;    for(i = 0; i < n; ++ i) rank[sa[i]] = i;    for(j = i = 0; i < n; ++ i)    {        if(rank[i] == 0) height[0] = j = 0;        else        {            for(k = sa[rank[i] - 1], j = max(j - 1, 0); s[i+j] && s[i+j] == s[k+j]; ++ j);            height[rank[i]] = j;        }    }}const int RMQ_N = 7 + 201000;int Log2[RMQ_N],Pow2[30];struct RMQ{    int st[RMQ_N][30],n,m;    int cmp(int a,int b)    {        return a<b ? a : b;    }    void init(int dig[],int n)    {        this->n=n;        Log2[1]=0;        for (int i=2; i<=n; i++) Log2[i]=Log2[i>>1]+1;        m=Log2[n];        Pow2[0]=1;        for (int i=1; i<30; i++) Pow2[i]=Pow2[i-1]<<1;        for (int i=1; i<=n; i++) st[i][0]=dig[i];        for (int j=1; j<=m; j++)            for (int i=1; i+Pow2[j]-1<=n; i++)                st[i][j]=cmp(st[i][j-1],st[i+Pow2[j-1]][j-1]);    }    int query(int l,int r)    {        if (l>r) swap(l,r);        int tmp = Log2[r-l+1];        return cmp(st[l][tmp],st[r-Pow2[tmp]+1][tmp]);    }}   rmq;int l[201000],r[201000],len[201000];char st[N];int main(){    int T,ca;    for (scanf("%d",&T),ca=1; ca<=T; ca++)    {        int n;        scanf("%d",&n);        r[0]=-1;        int mod=121;        for (int i=1; i<=n; i++)        {            l[i]=r[i-1]+1;            scanf(" %s",st+l[i]);            r[i]=l[i]+strlen(st+l[i])-1;            for (int j=l[i]; j<=r[i]; j++)                s[j]=st[j];            len[i]=r[i]-l[i]+1;            r[i]++;            mod++;            s[r[i]]=mod;        }        suffixarray(r[n],10300);        get_height(s,r[n]);        rmq.init(height,r[n]);        int m;        scanf("%d",&m);        printf("Case %d:\n",ca);        for (int i=1; i<=m; i++)        {            int x,y;            scanf("%d%d",&x,&y);            x++;            y++;            int a=rank[l[x]];            int b=rank[l[y]];            if (a>b) swap(a,b);            int ans;            if (a==b) ans=len[x];            else ans=rmq.query(a+1,b);            printf("%d\n",ans);        }    }    return 0;}



0 0
原创粉丝点击