1. 程式人生 > >2018.12.01【SPOJ220】Relevant Phrases of Annihilation(字尾陣列)(二分答案)

2018.12.01【SPOJ220】Relevant Phrases of Annihilation(字尾陣列)(二分答案)

傳送門


解析:

套路題。

首先串成一串求一下SA。

然後按照二分出的 l e n len ,根據 h e i

g h t height 陣列分組。

在每組裡面看 k k 個串是否分別滿足條件就行了。


程式碼:

#include<bits/stdc++.h>
using namespace std; #define ll long long #define re register #define gc getchar #define pc putchar #define cs const cs int N=100005; namespace SA{ char s[N]; int sa[N],rk[N],ht[N],len; int bin[N]; inline void radix_sort(int *cs x,int *cs y,int m,int n); inline void init(); inline bool check(int
x); } inline void SA::radix_sort(int *cs x,int *cs y,int m,int n){ memset(bin+1,0,sizeof(int)*m); for(int re i=1;i<=n;++i)++bin[x[i]]; for(int re i=1;i<=m;++i)bin[i]+=bin[i-1]; for(int re i=n;i;--i)sa[bin[x[y[i]]]--]=y[i]; } inline void SA::init(){ int *x=rk,*y=ht,n=len,m=256; for(int re i=1;i<=n;++i)x[i]=s[i],y[i]=i; radix_sort(x,y,m,n); for(int re i=1,cnt=0;i<=n&&cnt<n;i<<=1){ cnt=0; for(int re j=n-i+1;j<=n;++j)y[++cnt]=j; for(int re j=1;j<=n;++j)if(sa[j]>i)y[++cnt]=sa[j]-i; radix_sort(x,y,m,n); swap(x,y); x[sa[1]]=cnt=1; for(int re j=2;j<=n;++j)x[sa[j]]=((y[sa[j]]==y[sa[j-1]])&&(y[sa[j]+i]==y[sa[j-1]+i])?cnt:++cnt); m=cnt; } for(int re i=1;i<=n;++i)rk[sa[i]]=i; for(int re i=1,k=0,j;i<=len;ht[rk[i++]]=k) for(k?--k:0,j=sa[rk[i]-1];s[i+k]==s[j+k];++k); } int be[12],k; int l[12],id[N]; int maxn[12],minn[12]; inline bool SA::check(int x){ fill(maxn+1,maxn+k+1,0); fill(minn+1,minn+k+1,N); for(int re i=1;i<=len;++i){ if(ht[i]<x){ fill(maxn+1,maxn+k+1,0); fill(minn+1,minn+k+1,N); maxn[id[sa[i]]]=sa[i]; minn[id[sa[i]]]=sa[i]; } else{ maxn[id[sa[i]]]=max(maxn[id[sa[i]]],sa[i]); minn[id[sa[i]]]=min(minn[id[sa[i]]],sa[i]); maxn[id[sa[i-1]]]=max(maxn[id[sa[i-1]]],sa[i-1]); minn[id[sa[i-1]]]=min(minn[id[sa[i-1]]],sa[i-1]); for(int re j=1;j<=k;++j){ if(maxn[j]-minn[j]<x)break; if(j==k)return true; } } } return false; } int T; signed main(){ scanf("%d",&T); while(T--){ scanf("%d",&k);SA::len=0; memset(SA::s,0,sizeof SA::s); for(int re i=1;i<=k;++i){ SA::len++; scanf("%s",SA::s+SA::len); be[i]=SA::len; SA::len+=(l[i]=strlen(SA::s+SA::len)); for(int re j=be[i];j<SA::len;++j){ id[j]=i; } SA::s[SA::len]='$'+i; } SA::init(); re int l=0,r=10000; while(l<r){ int mid=(l+r+1)>>1; if(SA::check(mid))l=mid; else r=mid-1; } printf("%d\n",l); } return 0; }