Description
Solution
这道题目很容易就可以看出来需要求某几个trie上的最长公共子串,如果我们把trie建出来之后可以发现,目前需要克服的困难是多个串一起求lcp。
对于这个问题,我们可以把所有trie都合并在一起,对于每一个节点记录一下分别是哪些天出现过的,之后在这个trie上建一个后缀自动机。我们如何利用这个建出的自动机呢?可以发现,对于每一个节点我们都有一个状态标记,因为遍历自动机可以求出所有子串,那么只要判断当前串被哪些天包含就可以了。设一个FS表示当天数集合为S时,他们的最长子串是多长。注意
Code
#include<iostream>
#include<string.h>
#include<math.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
const int N=1e6+5,MX=(1<<20)+5;
struct nod1{
int son[26],fa,len,s;
}t[N*2];
struct nod2{
int son[26],s,fa;
}tr[N*2];
struct arr{
int x,len;
}a[N*2];
char s[N];
int c[N],D[N*2],la[N*2],cen[N],F[MX],L[N*2],las[N*2];
int n,Q,i,j,len,sum,num,p,np,q,nq,father,next;
bool bz,B[N*2];
bool cmp(arr x,arr y){return x.len>y.len;}
void add(int c,int &last,int S){
p=last,np=++sum;last=sum;
t[np].len=t[p].len+1;/**/t[np].s=S;/**/
while(p&&!t[p].son[c]) t[p].son[c]=np,p=t[p].fa;
if(!p) t[np].fa=1;
else{
q=t[p].son[c];
if(t[p].len+1==t[q].len) t[np].fa=q;
else{
t[nq=++sum]=t[q],t[nq].len=t[p].len+1;/**/t[nq].s=S;/**/
t[np].fa=t[q].fa=nq;
while(p&&t[p].son[c]==q) t[p].son[c]=nq,p=t[p].fa;
}
}
}
void trie(int now,int Day){
int i,x,y;
x=cen[now];now++;
if(!tr[x].son[c[now]]) tr[x].son[c[now]]=++sum,tr[sum].fa=x;
y=tr[x].son[c[now]];
tr[y].s=(tr[y].s|Day);
cen[now]=y;
}
void deal(){
int i,x,y,l=0,r=1;
D[1]=1;
while(l<r){
x=D[++l];
fo(i,0,25) if(tr[x].son[i]){
y=tr[x].son[i];
las[y]=las[x];
add(i,las[y],tr[y].s);
D[++r]=y;
}
}
fo(i,1,sum) a[i]=(arr){i,t[i].len};
sort(a+1,a+sum+1,cmp);
fo(i,1,sum){
x=a[i].x,y=t[x].fa,t[y].s=(t[y].s|t[x].s);
F[t[x].s]=(F[t[x].s]>t[x].len)?F[t[x].s]:t[x].len;
}
}
int main(){
freopen("wechat.in","r",stdin);
freopen("wechat.out","w",stdout);
sum=cen[0]=1;
scanf("%d",&n);
fo(i,1,n){
scanf("%s",s+1);len=strlen(s+1);num=0;
fo(j,1,len) if(s[j]!='<'){
c[++num]=s[j]-'a';
trie(num-1,1<<(i-1));
}else num--;
}
sum=next=las[1]=1;
deal();
fd(i,(1<<n)-1,0) fo(j,0,n-1) if(i&(1<<j))
F[i^(1<<j)]=max(F[i^(1<<j)],F[i]);
scanf("%d",&Q);
fo(i,1,Q){
scanf("%s",s+1);len=strlen(s+1);
num=0;
while(len) num=num*2+s[len]-'0',len--;
printf("%d\n",F[num]);
}
}