题面过长,略
先把n个串合并建出Trie. 由于n很小,对于Trie的每个节点,我们用状压记录这个节点代表的子串来自哪些串。然后BFS这个Trie,建出广义SAM.对于SAM中新建的每个节点,同样维护这个子串来自哪些串,构建的时候把它赋值为原Trie上的状态(复制出来的节点为0).然后在parent树上,把子树中的状态并上来。
接着设\(f[S]\)表示询问的串状态为\(S\)的答案。设后缀自动机上每个点的状态为\(S_x\),我们初始化\(f[S_x]=len(x)\).那么由于x代表在\(S_x\)中的每个串都存在,那么在\(S_x\)的子集中的每个串都存在。我们可以用\(f[S_x]\)去更新\(f[S_x-\{ i\}]\),即:
对于询问,直接输出对应的\(f\)即可。时间复杂度\(O(\sum |S|+2^n)\)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 2000000
#define maxc 26
#define maxs (1<<20)
using namespace std;
int n,m;
char in[maxn+5];
struct EXSAM{
#define len(x) t[x].len
#define link(x) t[x].link
struct node {
int ch[maxc];
int link;
int len;
int sta;
} t[maxn*2+5];
const int root=1;
int ptr=1;
int extend(int last,int c,int sta) {
int p=last,cur=++ptr;
len(cur)=len(p)+1;
t[cur].sta=sta;
while(p&&t[p].ch[c]==0) {
t[p].ch[c]=cur;
p=link(p);
}
if(p==0) link(cur)=root;
else {
int q=t[p].ch[c];
if(len(p)+1==len(q)) link(cur)=q;
else {
int clo=++ptr;
len(clo)=len(p)+1;
for(int i=0; i<maxc; i++) t[clo].ch[i]=t[q].ch[i];
link(clo)=link(q);
link(q)=link(cur)=clo;
while(p&&t[p].ch[c]==q) {
t[p].ch[c]=clo;
p=link(p);
}
}
}
return cur;
}
void topo_sort(){
static int in[maxn+5];
queue<int>q;
for(int i=1;i<=ptr;i++) in[link(i)]++;
for(int i=1;i<=ptr;i++) if(!in[i]) q.push(i);
while(!q.empty()){
int x=q.front();
q.pop();
in[link(x)]--;
t[link(x)].sta|=t[x].sta;
if(in[link(x)]==0) q.push(link(x));
}
}
}T1;
struct Trie{
int trie_pos[maxn+5],sam_pos[maxn+5];
int ch[maxn+5][maxc];
int sta[maxn+5];
const int root=1;
int ptr=1;
void insert(char *s,int id){
int top=0;
int len=strlen(s+1);
trie_pos[++top]=root;
for(int i=1;i<=len;i++){
if(s[i]==‘<‘) top--;
else{
int x=trie_pos[top],c=s[i]-‘a‘;
if(!ch[x][c]) ch[x][c]=++ptr;
x=ch[x][c];
sta[x]|=(1<<(id-1));
trie_pos[++top]=x;
}
}
}
void build(EXSAM &T1){
queue<int>q;
q.push(root);
sam_pos[root]=root;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<maxc;i++){
int y=ch[x][i];
if(y!=0){
sam_pos[y]=T1.extend(sam_pos[x],i,sta[y]);
q.push(y);
}
}
}
}
}T2;
int dp[maxs+5];
int query(char *s){
int len=strlen(s+1);
int x=0;
for(int i=len;i>=1;i--) x=x*2+s[i]-‘0‘;
return dp[x];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",in+1);
T2.insert(in,i);
}
T2.build(T1);
T1.topo_sort();
for(int i=1;i<=T1.ptr;i++) dp[T1.t[i].sta]=max(dp[T1.t[i].sta],T1.t[i].len);
for(int i=(1<<n)-1;i>=0;i--){
for(int j=0;j<n;j++){
if(i&(1<<j)) dp[i^(1<<j)]=max(dp[i^(1<<j)],dp[i]);
//如果一个串的出现状态为i
//那么询问它的子集i^(1<<j)的答案,就可以用这个串去更新
}
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%s",in+1);
printf("%d\n",query(in));
}
}
/*
2
ab<a
aac
2
01
*/
原文:https://www.cnblogs.com/birchtree/p/12555638.html