给定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 233 int 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 1000000007 int 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 1000000007 const 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; }
FZU problem 1985 LCP Problem
最新推荐文章于 2021-04-14 23:33:18 发布