【[USACO12DEC]第一!First!】
阿新 • • 發佈:2019-01-02
一個串不能成為第一的情況有兩種
另外一個單詞是它的字首
在分配字母表大小關係的時候出現了矛盾的情況
第一種很好判斷,一旦我們在一個單詞沒有匹配完之前遇到一個結束標誌,那麼就說明另外一個單詞是它的字首
至於第二種,看到大小關係和是否矛盾我們很容易就聯想到了拓撲排序
於是我們匹配的時候,發現某一層除了當前正在匹配的串以外還有其他字母,那麼這些字母在我們構建的字母表中必須大於當前的這個字母,於是我們連一條有向邊表示一下大小關係就好了
最後跑一遍拓撲判斷一下是否有環就好了
#include<cstring> #include<cstdio> #include<iostream> #include<string> #define re register #define maxn 300005 using namespace std; struct node { int v,nxt; }e[1005]; int son[maxn][26],flag[maxn]; std::string S[30005]; int len[30005]; int n,num,cnt,tot; int head[26]; int ans[maxn]; inline void add_edge(int x,int y) { e[++num].v=y; e[num].nxt=head[x]; head[x]=num; } inline void ins(int x) { int now=0; for(re int i=0;i<len[x];i++) { if(!son[now][S[x][i]-'a']) son[now][S[x][i]-'a']=++cnt; now=son[now][S[x][i]-'a']; } flag[now]=1; } inline int check(int x) { int now=0; memset(e,0,sizeof(e)); int c[26]; memset(c,0,sizeof(c)); memset(head,0,sizeof(head)); num=0; for(re int i=0;i<len[x];i++) { if(flag[now]) return 0; for(re int j=0;j<26;j++) if(son[now][j]&&S[x][i]-'a'!=j) add_edge(S[x][i]-'a',j),c[j]++; now=son[now][S[x][i]-'a']; } int cur=0; int q[27]; memset(q,0,sizeof(q)); for(re int i=0;i<26;i++) if(!c[i]) q[++cur]=i; for(re int i=1;i<=cur;i++) { for(re int j=head[q[i]];j;j=e[j].nxt) { c[e[j].v]--; if(!c[e[j].v]) q[++cur]=e[j].v; } } return cur==26; } int main() { ios::sync_with_stdio(false); cin>>n; for(re int i=1;i<=n;i++) { cin>>S[i]; len[i]=S[i].size(); ins(i); } tot=0; for(re int i=1;i<=n;i++) if(check(i)) ans[++tot]=i; cout<<tot<<endl; for(re int i=1;i<=tot;i++) cout<<S[ans[i]]<<endl; return 0; }