poj3294 Life Forms

来源:互联网 发布:app软件产品说明书 编辑:程序博客网 时间:2024/05/19 18:45

        题意:输入n个串,求一个长度最大的串,使得它在超过一半的串中连续出现。如果有多解,按字典序从小到大输出。

        思路:后缀数组。首先把所有原串拼接成一个长串,中间插入不同的没出现过的字符。然后对长串求后缀数组的height数组,二分答案,检查是否有该长度的串在超过一半的串中连续出现。方法是分段,每次发现height[i]<ans就划为一个新段,则每段前ans个字符全部相同。开一个数组来标记包含了哪些串。

        这是大白书后缀数组的例题。SA真是神一样的数据结构啊,太难看懂了,直到我发现了一个比较好理解的板子才看懂的。题目为什么能这样做呢,我们可以想象一颗后缀树,把拼接后的长串的所有后缀插入到一棵后缀树中(顺便领悟一下插入不同没出现过的字符的精妙)。前ans个字符相同的后缀,一定共用了ans个节点,如果哪个节点下面的分支非常多,那么就说明有多个这样的串了。height数组相当与保存了两个相邻叶子公共祖先的数量。

        写这题的时候我出现了三处错误,一是二分没有写好,有的值分不到;二是插入的字符从‘z’开始往后插,但是这样做会出现bug,可能是溢出了;三是分段时最后一段没分好。


#include <iostream>       #include <stdio.h>       #include <cmath>       #include <algorithm>       #include <iomanip>       #include <cstdlib>       #include <string>       #include <string.h>       #include <vector>       #include <queue>       #include <stack>       #include <map>     #include <set>     #include <ctype.h>       #include <sstream>   #define INF 1000000000   #define ll long long   #define min3(a,b,c) min(a,min(b,c))#define max3(a,b,c) max(a,max(b,c))     using namespace std;const int N=110000;struct SuffixArray{    int n,len,A[N],C[N],sa[N],rank[N],height[N];    struct RadixEle{        int id,k[2];        RadixEle(){}        RadixEle(int a,int b,int c){id=a;k[0]=b;k[1]=c;}    }RT[N],RE[N];    void RadixSort()    {        for(int y=1;y>=0;y--)        {            memset(C,0,sizeof(C));            for(int i=1;i<=n;i++) C[RE[i].k[y]]++;            for(int i=1;i<N;i++) C[i]+=C[i-1];            for(int i=n;i>=1;i--) RT[C[RE[i].k[y]]--]=RE[i];            for(int i=1;i<=n;i++) RE[i]=RT[i];        }        for(int i=1;i<=n;i++)        {            rank[RE[i].id]=rank[RE[i-1].id];            if(RE[i].k[0]!=RE[i-1].k[0]||RE[i].k[1]!=RE[i-1].k[1])                rank[RE[i].id]++;        }    }    void CalcSA(){        for(int i=1;i<=n;i++) RE[i]=RadixEle(i,A[i],0);        RadixSort();        for(int k=1;1+k<=n;k*=2)        {            for(int i=1;i<=n;i++) RE[i]=RadixEle(i,rank[i],(i+k<=n?rank[i+k]:0));            RadixSort();        }        for(int i=1;i<=n;i++) sa[rank[i]]=i;    }    void CalcHeight()    {        int h=0;        for(int i=1;i<=n;i++)        {            if(rank[i]==1) h=0;            else            {                int k=sa[rank[i]-1];                if(--h<0) h=0;                while(A[i+h]==A[k+h]) h++;            }            height[rank[i]]=h;        }    }}SA;char str[110000];int mp[110000];bool vis[110];int n;bool binaryans(int len){int s=1;int t=0;for(int j=1;j<=n;j++)vis[j]=0;for(int i=1;i<=SA.n;i++){vis[mp[SA.sa[i]]]=1;if(SA.height[i+1]<len||i==SA.n){int cnt=0;for(int j=1;j<=n;j++)if(vis[j])cnt++;if(cnt>n/2)return 1;for(int j=1;j<=n;j++)vis[j]=0;s=i;}t++;}return 0;}void printans(int len){for(int j=1;j<=n;j++)vis[j]=0;for(int i=1;i<=SA.n+1;i++){vis[mp[SA.sa[i]]]=1;if(SA.height[i+1]<len||i==SA.n){int cnt=0;for(int j=1;j<=n;j++)if(vis[j])cnt++;if(cnt>n/2){int s=SA.sa[i-1];for(int k=s;k<s+len;k++){printf("%c",str[k]);}printf("\n");cnt=0;}for(int j=1;j<=n;j++)vis[j]=0;}}}int main(){while(cin>>n){if(!n)break;char* s=str+1;int ins=1;for(int i=1;i<=n;i++){scanf("%s",s);int t=strlen(s);s[t]=ins++;if(ins=='a')ins='z'+1;s+=t+1;}int siz=strlen(str+1);int k=1;for(int i=1;i<=siz;i++){SA.A[i]=str[i];mp[i]=k;if(SA.A[i]<'a'||SA.A[i]>'z')k++;}SA.n=siz; SA.CalcSA();SA.CalcHeight();int l=0,r=siz/n;int ans=0;while(l<r){int mid=(l+r)/2;if(binaryans(mid)){ans=mid;l=mid+1;}else{r=mid;}}if(ans){printans(ans);}else{printf("?\n");}printf("\n");}return 0;}



0 0
原创粉丝点击