BZOJ3012 First!題解(Trie樹+拓撲排序)
阿新 • • 發佈:2019-01-13
題目:BZOJ3012.
題目大意:給定一些字串,求在每一個串是否能在一個字典順序下字典序最小.
這道題一看到要拓撲排序就懵了,想了一下如何建圖也沒有想出來,這種建圖的套路題做的少啊…
首先我們先確定一個性質,就是當一個串有一個字首串也在給定串中時,這個串肯定不可能字典序最小了.
於是我們就發現這道題要查一個串是否有字首也在給定串中,就可以很自然的想到Trie樹.
想到Trie樹後,我們考慮一個串字典序最小時,優先讓前面的最小,也就是說我們可以從Trie的根開始往下,與當前節點相連的每一層邊中,字典序最小的串所對應的邊必須是最小的.
這時我們就想到,可以建一張圖以每個字元作為一個節點,當一個字元x必須大於另一個字元y時就連一條從x到y的有向邊,那是否矛盾的問題就變成了判環問題,於是我們就可以愉快的寫拓撲排序判環了.時間複雜度 .
所以程式碼如下:
#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;
Trie(){m(s);cnt= 0;}
}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;
}