Loading

P3485 [POI2009] BAJ-The Walk of Bytie-boy 题解

暴力没前途,怎么可能,直接喜提最劣解。

思路

考虑一个最基本做法。

\(f_{i,j}\) 表示 \((i,j)\) 是回文路径的最小长度。

然后对每个二元组广搜。

拓展时暴力搜 \(i\) 的所有入边和 \(j\) 的所有出边。

这样是 \(O(m^2)\) 的。

但是我们会感到奇怪。

明明只有 \(n^2\) 个状态,为什么却花了 \(O(m^2)\) 的时间。

发现最大的时间损耗在我们的入边有可能和出边匹配过。

这样就有了很多无效的匹配。

怎么办。

使用 bitset!

我们将能匹配的出边用 bitset 存,每个点没有匹配过的点也用 bitset 存。

寻找的时候把两个与一下,找到里面的所有点即可。

时间复杂度降为了:\(O(\frac{mn^2}{w})\)

Code

/*
  ! 如果没有天赋,那就一直重复
  ! Created: 2024/06/26 09:26:19
*/
#include <bits/stdc++.h>
using namespace std;

#define x first
#define y second
// #define int long long
#define mp(x, y) make_pair(x, y)
#define eb(...) emplace_back(__VA_ARGS__)
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)
inline void JYFILE19();

using i64 = long long;
using u64 = unsigned long long;
using PII = pair<int, int>;

bool ST;
const int N = 410;
const int M = 60010;
const int mod = 998244353;

int n, m, d, ct, tt, tp, st[M], f[N][N], head[N], fead[N];
pair<PII, int> nt[N][N];
vector<int> res;
template<int T> struct Bitset {
  u64 v[T / 64 + 10], n, all;
  Bitset() { n = T / 64 + 1, all = -1; }
  inline void clr() { memset(v, 0, sizeof v); }
  inline void get() {
    res.clear();
    fro(i, 0, n) {
      if (v[i]) {
        auto x = v[i], lg = 1ull;
        while (x) lg = __lg(x), res.eb(lg + i * 64), x -= (1ull << lg);
      }
    }
  }
  inline void set(int x) { v[x>>6] ^= 1ull<<(x&63); }
  inline void operator&=(const Bitset<T> &tmp) { fro(i, 0, n) v[i] &= tmp.v[i]; }
};
Bitset<401> w, g[27], vs[401];

struct edge {
  int to, nxt, val;
} e[M << 1], p[M << 1];

inline void add(int x, int y, int z) {
  e[++ct] = {y, head[x], z}, head[x] = ct;
  p[++tt] = {x, fead[y], z}, fead[y] = ct;
}
inline void sol(int l, int r) {
  int L, R;
  tie(L, R) = nt[l][r].x;
  st[++tp] = nt[l][r].y;
  if (L == l && r == R) return;
  sol(L, R);
}

signed main() {
  JYFILE19();
  cin >> n >> m;
  fro(i, 1, m) {
    int x, y; char c;
    cin >> x >> y >> c;
    add(x, y, c - 'a');
  }
  queue<PII> q;
  fro(i, 1, n) fro(j, 1, n) if (i != j) vs[i].set(j);
  fro(i, 1, n) {
    for (int j = head[i]; j; j = e[j].nxt) {
      if (f[i][e[j].to] == 0) {
        f[i][e[j].to] = 1;
        nt[i][e[j].to] = {{i, e[j].to}, e[j].val};
        vs[i].set(e[j].to);
        q.emplace(i, e[j].to);
      }
    }
  }
  fro(i, 1, n) {
    for (int j = head[i]; j; j = e[j].nxt)
      for (int k = head[e[j].to]; k; k = e[k].nxt) {
        if (f[i][e[k].to] == 0 && e[j].val == e[k].val) {
          f[i][e[k].to] = 2;
          nt[i][e[k].to] = {{i, e[k].to}, e[k].val};
          vs[i].set(e[k].to);
          q.emplace(i, e[k].to);
        }
      }
  }
  while (q.empty() == 0) {
    int l, r;
    tie(l, r) = q.front(), q.pop();
    fro(i, 0, 25) g[i].clr();
    for (int i = head[r]; i; i = e[i].nxt) {
      g[e[i].val].set(e[i].to);
    }
    for (int i = fead[l]; i; i = p[i].nxt) {
      w = vs[p[i].to], w &= g[p[i].val], w.get();
      for (auto j : res) {
        f[p[i].to][j] = f[l][r] + 2;
        nt[p[i].to][j] = {{l, r}, p[i].val};
        vs[p[i].to].set(j);
        q.emplace(p[i].to, j);
      }
    }
  }
  cin >> d;
  for (int i = 1, las = 0; i <= d; i++) {
    int x; cin >> x;
    if (i > 1) {
      if (f[las][x]) {
        cout << f[las][x] << " ", tp = 0, sol(las, x);
        fro(i, 1, tp) cout << (char)(st[i] + 'a');
        if (f[las][x] % 2 == 0) cout << (char)(st[tp] + 'a');
        pre(i, tp, 2) cout << (char)(st[i - 1] + 'a');
        cout << "\n";
      } else {
        cout << -1 << "\n";
      }
    }
    las = x;
  }
  return 0;
}

bool ED;
inline void JYFILE19() {
  // freopen("", "r", stdin);
  // freopen("", "w", stdout);
  srand(random_device{}());
  ios::sync_with_stdio(0), cin.tie(0);
  double MIB = fabs((&ED - &ST) / 1048576.), LIM = 32;
  cerr << "MEMORY: " << MIB << endl, assert(MIB <= LIM);
}
posted @ 2024-06-26 11:04  JiaY19  阅读(2)  评论(0编辑  收藏  举报