不太记得当时怎么想的了,但是显然,当一个字符串的前缀存在则他一定不是first,然后做法:对于每个字符串,把每个字符结尾跟他有相同前缀的单词的同元素建边,保证这个元素严格大于其他元素,然后判环,有环的话说明不能是first,反之则是。
代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <vector> #include <string> #include <queue> #include <iostream> const int N=3e4+5,M=3e5+5; using namespace std; int n,m,tot,num,ss[N],vis[N],rd[26]; string s,dic[N]; vector <int> g[26]; namespace trietree { struct trie { int son[26],tag; }e[M]; void insert(int len) { int p=0; for(int i=0;i<len;i++) { int k=s[i]-'a'; if(!e[p].son[k]) e[p].son[k]=++tot; p=e[p].son[k]; } e[p].tag=1; } bool topusort() { queue <int> q; while(!q.empty()) q.pop(); int cnt=0; for(int i=0;i<26;i++) if(!rd[i]) q.push(i); while(!q.empty()) { int now=q.front(); int len=g[now].size(); ++cnt; q.pop(); for(int i=0;i<len;i++) { int k=g[now][i]; --rd[k]; if(!rd[k]) q.push(k); } } return cnt==26; } void clear(int len,int id) { int p=0,ok=0; s=dic[id]; for(int i=0;i<26;i++) g[i].clear(),rd[i]=0; for(int i=0;i<len;i++) { if(e[p].tag) ok=1; int k=s[i]-'a'; for(int j=0;j<26;j++) if(j!=k && e[p].son[j]) g[k].push_back(j),rd[j]++; p=e[p].son[k]; } if(!topusort()) ok=1; if(ok) vis[id]=1; num+=ok; } } using namespace trietree; int main() { ios::sync_with_stdio(0); cin>>n; for(int i=1;i<=n;i++) { cin>>s; ss[i]=s.length(); dic[i]=s; insert(ss[i]); } for(int i=1;i<=n;i++) clear(ss[i],i); cout<<n-num<<'\n'; for(int i=1;i<=n;i++) if(!vis[i]) cout<<dic[i]<<'\n'; return 0; }