USACO2012 Dec - First!

题目

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';
}

猜你喜欢

转载自www.cnblogs.com/arg-53/p/9062122.html
DEC