【刷題】BZOJ 1195 [HNOI2006]最短母串
阿新 • • 發佈:2018-07-12
getchar() n) init double gist c++ 超過 字典序 ble
然後開始BFS,直到搜到所有包括了所有串的結尾標記。BFS保證長度最小,從A到Z枚舉保證字典序最小
然後是關於結尾標記的轉移
考慮AC自動機fail樹的性質, \(u\) 的fail指針指向了 \(v\) ,說明 \(v\) 代表的串一定是 \(u\) 代表的串的後綴,那麽如果走到 \(u\) 節點,那麽就一定會包括了 \(v\) 代表的串,所以完全可以把 \(v\) 的結尾標記轉移給 \(u\)
Description
給定n個字符串(S1,S2,?,Sn),要求找到一個最短的字符串T,使得這n個字符串(S1,S2,?,Sn)都是T的子串。
Input
第一行是一個正整數n(n<=12),表示給定的字符串的個數。
以下的n行,每行有一個全由大寫字母組成的字符串。每個字符串的長度不超過50.
Output
只有一行,為找到的最短的字符串T。在保證最短的前提下,
如果有多個字符串都滿足要求,那麽必須輸出按字典序排列的第一個。
Sample Input
2
ABCD
BCDABC
Sample Output
ABCDABC
Solution
AC自動機上進行狀壓BFS
把所有的串插入AC自動機,每個串結尾標記
然後是關於結尾標記的轉移
考慮AC自動機fail樹的性質, \(u\) 的fail指針指向了 \(v\) ,說明 \(v\) 代表的串一定是 \(u\) 代表的串的後綴,那麽如果走到 \(u\) 節點,那麽就一定會包括了 \(v\) 代表的串,所以完全可以把 \(v\) 的結尾標記轉移給 \(u\)
#include<bits/stdc++.h> #define ui unsigned int #define ll long long #define db double #define ld long double #define ull unsigned long long int n,cnt,ch[601][27],fail[601],ed[601],pt[600*(1<<12)+1],len; bool vis[601][(1<<12)+1]; char s[601],p[600*(1<<12)+1]; struct node{ int x,su,ps; }; template<typename T> inline void read(T &x) { T data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar(); x=data*w; } template<typename T> inline void write(T x,char ch='\0') { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(ch!='\0')putchar(ch); } template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);} template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);} template<typename T> inline T min(T x,T y){return x<y?x:y;} template<typename T> inline T max(T x,T y){return x>y?x:y;} inline void init() { for(register int i=0,lt=strlen(s);i<lt;++i)s[i]-='A'-1; } inline void insert(int rk) { int x=0; for(register int i=0,lt=strlen(s);i<lt;++i) if(!ch[x][s[i]])x=ch[x][s[i]]=++cnt; else x=ch[x][s[i]]; ed[x]|=1<<rk-1; } inline void getfail() { static std::queue<int> q; for(register int i=1;i<=26;++i) if(ch[0][i])q.push(ch[0][i]); while(!q.empty()) { int x=q.front(); q.pop(); for(register int i=1,y,z;i<=26;++i) if(ch[x][i]) { y=ch[x][i],z=fail[x]; while(z&&!ch[z][i])z=fail[z]; fail[y]=ch[z][i]; ed[y]|=ed[fail[y]]; q.push(y); } else ch[x][i]=ch[fail[x]][i]; } } inline void solve() { static std::queue<node> q;cnt=0; q.push((node){0,0,0}); vis[0][0]=1; while(!q.empty()) { node pr=q.front(); q.pop(); int x=pr.x,now=pr.su,ip=pr.ps; if(now==(1<<n)-1) { for(;ip;ip=pt[ip])s[++len]=p[ip]; return ; } for(register int i=1,nxt;i<=26;++i) if(!vis[ch[x][i]][nxt=now|ed[ch[x][i]]]) { vis[ch[x][i]][nxt]=1; p[++cnt]=i+'A'-1,pt[cnt]=ip; q.push((node){ch[x][i],nxt,cnt}); } } } int main() { read(n); for(register int i=1;i<=n;++i)scanf("%s",s),init(),insert(i); getfail(),solve(); for(register int i=len;i>=1;--i)putchar(s[i]);puts(""); return 0; }
【刷題】BZOJ 1195 [HNOI2006]最短母串