题目:BZOJ3012.
题目大意:给定
n
n
n个字符串
S
i
S_i
Si,求在每一个串是否能在一个字典顺序下字典序最小.
1
≤
n
≤
3
∗
1
0
4
,
1
≤
∑
∣
S
i
∣
≤
3
∗
1
0
5
1\leq n\leq3*10^4,1\leq \sum |S_i|\leq 3*10^5
1≤n≤3∗104,1≤∑∣Si∣≤3∗105.
这道题一看到要拓扑排序就懵了,想了一下如何建图也没有想出来,这种建图的套路题做的少啊…
首先我们先确定一个性质,就是当一个串有一个前缀串也在给定串中时,这个串肯定不可能字典序最小了.
于是我们就发现这道题要查一个串是否有前缀也在给定串中,就可以很自然的想到Trie树.
想到Trie树后,我们考虑一个串字典序最小时,优先让前面的最小,也就是说我们可以从Trie的根开始往下,与当前节点相连的每一层边中,字典序最小的串所对应的边必须是最小的.
这时我们就想到,可以建一张图以每个字符作为一个节点,当一个字符 x x x必须大于另一个字符 y y y时就连一条从 x x x到 y y y的有向边,那是否矛盾的问题就变成了判环问题,于是我们就可以愉快的写拓扑排序判环了.
时间复杂度 O ( 26 m + 2 6 2 n ) O(26m+26^2n) O(26m+262n).
所以代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
#define m(a) memset(a,0,sizeof(a))
const int N=30000,M=300000,C=26;
struct Trie{
int s[C],cnt;
}tr[M+9];
int cn;
void Build(){tr[cn=1]=Trie();}
void Insert(char *c,int len){
int x=1;
for (int i=1;i<=len;++i)
if (tr[x].s[c[i]-'a']) x=tr[x].s[c[i]-'a'];
else {
tr[x].s[c[i]-'a']=++cn;
tr[cn]=Trie();
x=cn;
}
++tr[x].cnt;
}
int e[C+9][C+9],deg[C+9];
queue<int>q;
bool topsort(){
for (int i=0;i<C;++i)
if (!deg[i]) q.push(i);
int t;
while (!q.empty()){
t=q.front();q.pop();
for (int i=0;i<C;++i)
if (e[t][i]){
deg[i]-=e[t][i];
if (!deg[i]) q.push(i);
}
}
for (int i=0;i<C;++i)
if (deg[i]) return false;
return true;
}
bool Check(char *c,int len){
int x=1;
for (int i=0;i<C;++i){
for (int j=0;j<C;++j)
e[i][j]=0;
deg[i]=0;
}
for (int i=1;i<=len;++i)
if (tr[x].s[c[i]-'a']){
if (tr[x].cnt) return false;
for (int j=0;j<C;++j)
if (c[i]-'a'^j&&tr[x].s[j]) ++e[c[i]-'a'][j],++deg[j];
x=tr[x].s[c[i]-'a'];
}else break;
return topsort();
}
vector<char> c[N+9],ans[N+9];
char tmp[M+9];
int len[N+9],n,m;
int la[N+9],k;
Abigail into(){
scanf("%d",&n);
Build();
for (int i=1;i<=n;++i){
scanf("%s",tmp+1);
len[i]=strlen(tmp+1);
Insert(tmp,len[i]);
c[i].push_back(0);
for (int j=1;j<=len[i];++j)
c[i].push_back(tmp[j]);
}
}
Abigail work(){
for (int i=1;i<=n;++i){
for (int j=1;j<=len[i];++j)
tmp[j]=c[i][j];
if (!Check(tmp,len[i])) continue;
la[++k]=len[i];
ans[k].push_back(0);
for (int j=1;j<=len[i];++j)
ans[k].push_back(tmp[j]);
}
}
Abigail outo(){
printf("%d\n",k);
for (int i=1;i<=k;++i){
for (int j=1;j<=la[i];++j)
putchar(ans[i][j]);
puts("");
}
}
int main(){
into();
work();
outo();
return 0;
}