链接:https://www.nowcoder.com/acm/contest/59/B
来源:牛客网
题目描述
给定n个字符串,互不相等,你可以任意指定字符之间的大小关系(即重定义字典序),求有多少个串可能成为字典序最小的串,并输出它们
输入描述:
第一行一个数表示n
之后n行每行一个字符串表示给定的字符串
输出描述:
第一行输出一个数x表示可行的字符串个数
之后输出x行,每行输出一个可行的字符串
输出的顺序和输入的顺序一致
示例1
输入
6 mcfx ak ioi wen l a
输出
5 mcfx ioi wen l a
备注:
对于100%的数据,
n <= 30000 , 字符串总长<= 300000
字符集为小写字符
题目很是扯淡,,数据更扯淡,,不知道字符最大长度,MLE了几次,改小了又WA,还好最后试对了= =要是给出字符串最大长度就好了。
比赛时根本不知道题目在说什么鬼,其实就是询问某个字符串是否能最小,考虑作为最小的条件,S(最小)与另个字符串P比较时,遇到的第一个不相等的字符(位置j)时,S[j]<P[j]要成立,
我们将所有的字符串建成一颗trie时,对于某个被当做最小的字母,经过的所有的节点都要小于它的兄弟节点。暴力的找一下每个节点的兄弟建图即可。e[i][j]=1表示字符i<j成立。
我们只要找到所有的这些条件,在讨论是否能同时满足即可,这个问题显然就是拓扑排序,只要不出现环即可,问题转化为找图中是否有环。用floyd传递闭包即可。这个题有点卡时空。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX_SIG=26; 4 const int MAX_NOD=250000; 5 char str[30005][25]; 6 bool ok[30005]; 7 int ch[MAX_NOD][MAX_SIG]; 8 int val[MAX_NOD],sz; 9 char s[MAX_NOD]; 10 int e[30][30]; 11 int idx(char c){return c-'a';} 12 13 void _insert(char *s) 14 { 15 int u=0,n=strlen(s); 16 for(int i=0;i<n;++i){ 17 int c=idx(s[i]); 18 if(!ch[u][c]) ch[u][c]=sz++; 19 u=ch[u][c]; 20 } 21 val[u]++; 22 } 23 24 bool solve(int k) 25 { 26 memset(e,0,sizeof(e)); 27 int n=strlen(str[k]); 28 int u=0; 29 for(int i=0;i<n;++i){ 30 int c=idx(str[k][i]); 31 if(val[ch[u][c]]&&i!=n-1) return 0; 32 for(int j=0;j<MAX_SIG;++j){ 33 if(j==c) continue; 34 if(ch[u][j]) e[c][j]=1; 35 } 36 u=ch[u][c]; 37 } 38 for(int k=0;k<MAX_SIG;++k) 39 { 40 for(int i=0;i<MAX_SIG;++i) 41 { 42 if(!e[i][k]) continue; 43 for(int j=0;j<MAX_SIG;++j) 44 { 45 if(e[k][j]&&e[j][i]) return 0; 46 } 47 } 48 for(int i=0;i<MAX_SIG;++i) 49 { 50 if(!e[i][k]) continue; 51 for(int j=0;j<MAX_SIG;++j) 52 { 53 if(e[k][j]) e[i][j]=1; 54 } 55 } 56 } 57 return 1; 58 } 59 60 int main() 61 { 62 int n; 63 while(cin>>n){ 64 sz=1; 65 for(int i=1;i<=n;++i){ 66 scanf("%s",str[i]); 67 _insert(str[i]); 68 } 69 int ans=0; 70 for(int i=1;i<=n;++i){ 71 int k=solve(i); 72 if(k){ 73 ok[i]=1; 74 ans++; 75 } 76 } 77 cout<<ans<<endl; 78 for(int i=1;i<=n;++i) 79 if(ok[i]) cout<<str[i]<<endl; 80 } 81 return 0; 82 }