E. 最短母串
题目描述
输入格式
输出格式
样例
数据范围与提示
AC自动机+状压dp。其实也不算是dp,没有状态转移方程,就是用到了状压的思路。
网上大部分题解用的数组版AC自动机,看的我好难受…
设f[i][j]为在trie图上i节点状态为j时的最短长度,插入和求fail指针时顺便求出到某个点能覆盖的字符串,指针实现时trie图中要多维护一些东西:id=++cnt(f数组用),val(字符串),ooo(此节点表示的字符),然后bfs,定义两个队列分别存储节点和当前状态,不断扩展,由于是bfs,当状态为全部含有时即为最优解。关键在于字符串的输出,可以直接记录s[i][j]为在trie图上i节点状态为j时的字符串,但是比较占内存,是可以被卡掉的,所以可以记录trie *jl[10000][1<<13](
i节点状态为j时
的上一个节点),sta[10000][1<<13](
,输出:i节点状态为j时
的上一个状态)
1 if(state==maxn) 2 { 3 head=0; 4 while(p!=root) 5 { 6 q1[++head]=p; 7 int temp=sta[p->id][state]; 8 p=jl[p->id][state]; 9 state=temp; 10 } 11 while(head)putchar((char)q1[head--]->ooo+'A'); 12 return; 13 }
完整代码
#include<iostream> #include<cstdio> #include<bitset> #include<cstring> using namespace std; int cnt; struct trie { int count,id,val,ooo; trie *fail,*next[26]; trie() { id=++cnt; ooo=count=0;fail=NULL; for(int i=0;i<26;i++) next[i]=NULL; } }*q[10000000],*root=new trie(); int head,tail; void insert(char s[],trie *root,int t) { trie *p=root; int i=0,index; while(s[i]) { index=s[i]-'A'; if(p->next[index]==NULL)p->next[index]=new trie(); p->next[index]->ooo=index; p->next[index]->val|=p->val; p=p->next[index]; i++; } p->count++; p->val|=1<<(t-1); } void build_ac(trie *root) { head=tail=0; q[++tail]=root; while(head!=tail) { trie *p=q[++head]; for(int i=0;i<26;i++) if(p->next[i]) { if(p==root) p->next[i]->fail=p; else p->next[i]->fail=p->fail->next[i]; p->next[i]->val|=p->next[i]->fail->val; q[++tail]=p->next[i]; } else if(p==root) p->next[i]=p; else p->next[i]=p->fail->next[i]; } } int n; char keyword[100]; int f[10000][1<<13]; trie *jl[10000][1<<13]; int sta[10000][1<<13]; trie *q1[10000000]; int q2[10000000]; int inf,maxn; void bfs() { head=tail=0; q1[++tail]=root;q2[tail]=0; f[1][0]=0; while(head!=tail) { trie *p=q1[++head]; int state=q2[head]; bitset<4> tt(state); if(state==maxn) { head=0; while(p!=root) { q1[++head]=p; int temp=sta[p->id][state]; p=jl[p->id][state]; state=temp; } while(head)putchar((char)q1[head--]->ooo+'A'); return; } for(int i=0;i<26;i++) { int id=p->next[i]->id; if(f[id][state|p->next[i]->val]==inf) { q1[++tail]=p->next[i]; q2[tail]=state|p->next[i]->val; f[id][state|p->next[i]->val]=f[p->id][state]+1; jl[id][state|p->next[i]->val]=p; sta[id][state|p->next[i]->val]=state; } } } } signed main() { //freopen("in.txt","r",stdin); cin>>n; for(int i=1;i<=n;i++) { scanf("%s",keyword); insert(keyword,root,i); } build_ac(root); inf=f[0][0]; maxn=(1<<(n))-1; bfs(); }