题目描述
Bessie一直在研究字符串。她发现,通过改变字母表的顺序,她可以按改变后的字母表来排列字符串(字典序大小排列)。
例如,Bessie发现,对于字符串串“omm”,“moo”,“mom”和“ommnom”,她可以使用标准字母表使“mom”排在第一个(即字典序最小),她也可以使用字母表“abcdefghijklonmpqrstuvwxyz”使得“omm”排在第一个。然而,Bessie想不出任何方法(改变字母表顺序)使得“moo”或“ommnom”排在第一个。
接下来让我们通过重新排列字母表的顺序来计算输入中有哪些字符串可以排在第一个(即字典序最小),从而帮助Bessie。
要计算字符串X和字符串Y按照重新排列过的字母表顺序来排列的顺序,先找到它们第一个不同的字母X[i]与Y[i],按重排后的字母表顺序比较,若X[i]比Y[i]先,则X的字典序比Y小,即X排在Y前;若没有不同的字母,则比较X与Y长度,若X比Y短,则X的字典序比Y小,即X排在Y前。
数据范围
第1行:一个数字N(1 <= N <= 30,000),Bessie正在研究的字符串的数量。
第2~N+1行:每行包含一个非空字符串。所有字符串包含的字符总数不会超过300,000。 输入中的所有字符都是小写字母,即a~z。 输入不包含重复的字符串。
分析
- 题目看一眼之后,由于需要比较两个字符串的大小且仅有26个字母,所以想到用字典树来维护这个所有信息。
- 对于一个字符串能否成为字典序最小的字符串有两种判断:1.如果存在它的前缀那么显然是不能的。2.两个字符串存在相同的前缀,那么只需确定它们后一位的大小关系是否和前面确定的关系矛盾。
#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
int _read(){
char ch = getchar();
int x = 0 , f = 1 ;
while( !isdigit( ch ) )
if( ch == '-' ) f = -1 , ch = getchar();
else ch = getchar();
while( isdigit( ch ) )
x = (ch - '0') + x * 10 , ch = getchar();
return x * f;
}
const int maxn = 300000 + 5 , maxl = 2000 + 5;
char s[maxn][300];
int rd[maxl];
struct edge{
int v , nxt;
} e[maxl];
int head[maxl] , _t = 0;
inline void addedge( int u , int v ){
e[_t].v = v , e[_t].nxt = head[u] , head[u] = _t++;
}
bool val[maxn];
int T[maxn][26] , cnt = 0 ;
void ins( int x ){
int l = strlen( s[x] + 1 ) , cur = 0;
rep( i , 1 , l ){
int p = s[x][i] - 'a';
if( !T[cur][p] ) T[cur][p] = ++cnt;
cur = T[cur][p];
}
val[cur] = 1;
}
inline bool ck( int x ){
int l = strlen( s[x] + 1 ) , cur = 0;
rep( i , 1 , l ){
int p = s[x][i] - 'a';
if( val[cur] ) return false;
rep( j , 0 , 25 ) if( p != j && T[cur][j] ) addedge( p + 1 , j + 1 ) , rd[j + 1]++;
cur = T[cur][p];
}
return true;
}
bool topo(){
queue<int> q;
rep( i , 1 , 26 ) if( !rd[i] ) q.push(i);
while( !q.empty() ){
int cur = q.front(); q.pop();
erep( i , cur ){
int v = e[i].v;
if( rd[v] ){
rd[v]--;
if( !rd[v] ) q.push( v );
}
}
}
rep( i , 1 , 26 ) if( rd[i] ) return 0;
return 1;
}
int ans[maxn];
int main(){
int N;
scanf("%d\n" , &N);
rep( i , 1 , N ){
scanf("%s" , s[i] + 1);
ins( i );
}
int c = 0;
rep( i , 1 , N ){
memset( head , 0xff , sizeof head );
memset( e , 0 , sizeof e );
memset( rd , 0 , sizeof rd );
_t = 0;
if( ck( i ) && topo() ) ans[++c] = i;
}
printf("%d\n" , c);
rep( i , 1 , c )
printf("%s\n" , s[ans[i]] + 1);
return 0;
}