题目
https://www.luogu.org/problemnew/show/P3065
题解
利用所有字符串建一棵字典树,考虑当前这个节点下的所有儿子:若某个儿子下的某个字符串排第一位,那么这个儿子的字典序一定小于其他儿子,按照 钦定的儿子 -> 其他儿子 这种方式连边,然后到字典树上某个串的结尾时做一遍拓扑排序判环,有环的话说明规定的字典序有矛盾,也就不可能使这个字符串排第一位了。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (n); ++i)
struct node_t {
node_t* ch[26];
int id;
node_t() : id(-1) {}
};
int N;
string S[30010];
node_t mem[300010], *pool = mem;
bool g[26][26];
bool good[30010];
int que[26];
int deg[26];
int ans;
bool check() {
memset(deg, 0, sizeof(deg));
rep(a, 26) {
for (int b = a + 1; b < 26; ++b) {
if (g[a][b] && g[b][a]) return false;
if (g[a][b]) ++deg[b];
else if (g[b][a]) ++deg[a];
}
}
int qt = 0;
rep(c, 26) if (deg[c] == 0) que[qt++] = c;
rep(i, qt) {
int u = que[i];
rep(v, 26) {
if (!g[u][v]) continue;
--deg[v];
if (deg[v] == 0) que[qt++] = v;
}
}
return qt == 26;
}
void dfs(node_t* o) {
if (o->id != -1) {
if (check()) good[o->id] = true, ++ans;
return;
}
bool* mark = new bool[26];
rep(a, 26) {
if (!o->ch[a]) continue;
rep(b, 26) {
if (a == b || !o->ch[b]) continue;
if (!g[a][b]) {
g[a][b] = true;
mark[b] = true;
}
}
dfs(o->ch[a]);
rep(b, 26) {
if (a == b || !o->ch[b]) continue;
if (mark[b]) {
mark[b] = false;
g[a][b] = false;
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> N;
node_t* root = pool++;
rep(i, N) {
string& s = S[i];
cin >> s;
int L = s.size();
node_t* o = root;
rep(j, L) {
node_t*& c = o->ch[s[j] - 'a'];
if (!c) c = pool++;
o = c;
}
o->id = i;
}
dfs(root);
cout << ans << '\n';
rep(i, N) if (good[i]) cout << S[i] << '\n';
}