1. 程式人生 > 實用技巧 >P3065 [USACO12DEC]First! G

P3065 [USACO12DEC]First! G

Trie+拓撲排序。
P3065 USACO12DECFirst! G
假定當前字串是最小的,然後在Trie上跑一遍,字典序小的字母向字典序大的字母連邊。
然後拓撲排序成環就與猜測衝突(即不能為最小的)
注:字典序先按字母排序,然後按長度。
所以遇到字首相同的,長的必定不行。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

struct nod {
    ll nt[26], vis;
} t[MAXN];

struct edge {
    ll nt, to;
} E[MAXN];

ll N, cnt = 0, rk[26], head[26], ecnt = -1, tot, ans[MAXN];
string ss[MAXN];

void add(ll, ll);
bool check(string);
void inser(string);
bool tope();

int main() {
    cin >> N;
    for (ll i = 1; i <= N; i++) {
        cin >> ss[i];
        inser(ss[i]);
    }
    for (ll i = 1; i <= N; i++) {
        memset(rk, 0, sizeof(rk));
        memset(head, -1, sizeof(head));
        ecnt = -1;
        if (check(ss[i])) {
            if (tope()) {
                ans[++tot] = i;
            }
        }
    }
    cout << tot << endl;
    for (ll i = 1; i <= tot; i++) {
        cout << ss[ans[i]] << endl;
    }
    return 0;
}

bool tope() {
    stack<ll> st;
    for (ll i = 0; i < 26; i++) {
        if (!rk[i]) {
            st.push(i);
        }
    }
    while (!st.empty()) {
        ll nt = st.top(); st.pop();
        for (ll i = head[nt]; ~i; i = E[i].nt) {
            ll v = E[i].to;
            rk[v]--;
            if (!rk[v]) st.push(v);
        }
    }
    for (ll i = 0; i < 26; i++) {
        if (rk[i]) {
            return false;
        }
    }
    return true;
}

bool check(string tem) {
    ll len = tem.length(), now = 0;
    for (ll i = 0; i < len; i++) {
        ll gg = tem.at(i) - 'a';
        if (t[now].vis) return false;
        for (ll i = 0; i < 26; i++) {
            if (t[now].nt[i] && gg != i) {
                add(gg, i);
            }
        }
        now = t[now].nt[gg];
    }
    return true;
}

void add(ll x, ll y) {
    ecnt++;
    E[ecnt].nt = head[x];
    E[ecnt].to = y;
    rk[y]++;
    head[x] = ecnt;
}

void inser(string tem) {
    ll now = 0, len = tem.length();
    for (ll i = 0; i < len; i++) {
        ll gg = tem.at(i) - 'a';
        if (!t[now].nt[gg]) {
            t[now].nt[gg] = ++cnt;
        }
        now = t[now].nt[gg];
    }
    t[now].vis = 1;
}