时空限制 1000ms / 32MB
题目描述![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/231392ed580fd91872d71fc50fe75efc.png)
输入格式:
输出格式:
题目分析
一开始建trie树时的标记节点用一个二进制状态记录单词出现情况
构造AC自动机的时候把这些标记一起转移
然后从根开始按字典序BFS
不知道为啥BZOJ玄学T,似乎不是算法的问题,编译器之类的锅??
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=1010;
int n;
int ch[maxn][26],rem[maxn];
int fail[maxn],cnt;
int vis[maxn][1<<14];
char pt[55];
struct node{int u,st,id;};
int pre[2000010],a[2000010];
void print(int x)
{
if(!x) return;
print(pre[x]);
printf("%c",a[x]+'A');
}
void ins(char* ss,int len,int id)
{
int u=0;
for(int i=0;i<len;++i)
{
int x=ss[i]-'A';
if(!ch[u][x]) ch[u][x]=++cnt;
u=ch[u][x];
}
rem[u]|=1<<id-1;
}
void ACM()
{
queue<int> q;
for(int i=0;i<26;++i)
if(ch[0][i]) fail[ch[0][i]]=0,q.push(ch[0][i]);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=0;i<26;++i)
{
if(!ch[u][i]) ch[u][i]=ch[fail[u]][i];
else{
fail[ch[u][i]]=ch[fail[u]][i];
q.push(ch[u][i]);
//if(rem[fail[ch[u][i]]])
//rem[ch[u][i]]|=rem[fail[ch[u][i]]];
}
}
int tt=fail[u];
while(tt&&!rem[tt]) tt=fail[tt];
rem[u]|=rem[tt];
}
}
void BFS()
{
queue<node> q;
q.push((node){0,rem[0],0});
vis[0][rem[0]]=1; int tot=0;
while(!q.empty())
{
node x=q.front(); q.pop();
int u=x.u,st=x.st,last=x.id;
if(st==(1<<n)-1){ print(last); return;}
for(int i=0;i<26;i++)
{
int nxt=st|rem[ch[u][i]];
if(vis[ch[u][i]][nxt]) continue;
vis[ch[u][i]][nxt]=1;
pre[++tot]=last; a[tot]=i;
q.push((node){ch[u][i],nxt,tot});
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;++i)
{
scanf("%s",pt);
ins(pt,strlen(pt),i);
}
ACM(); BFS();
return 0;
}