C+K+S

这个题还真挺不错的,值得补出来!

我们可以钦定任意一点的颜色(取值为 ),然后沿着边的方向对其他点染色。具体地,第设 个点的颜色为 ,且有一条边 ,则 。这个图上的所有环长度都是 的倍数,因此一定可以按照上述规则对该图染色。

一个图有且仅有 种染色方式,构造出一组 后可以通过 构造出来所有其他的染色方式。

我们在加边的时候遵循相同的规则,从颜色 连接到 ,这样构造出来的图肯定也能满足所有的环为 的倍数。

一种暴力做法是,枚举两个图的所有染色形式,检查:对于每种颜色 ,图一中颜色为 的 outgoing 点数量是否等于图二颜色为 的 incoming 点数量,且图而中颜色为 的 outgoing 点数量是否等于图一颜色为 的 incoming 点数量。其时间复杂度为 。两个图同时偏移相同的数时,效果相同。所以,我们只需要枚举某一个图的染色方式即可。这样的复杂度为

观察一下统计每种颜色 incoming 点数量与 outgoing 点数量的数组,所有点颜色增加 相当于数组循环移位一次。而我们只需要判两个数组是否相等,上哈希搞一下就好了。

#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <iostream>
#include <queue>
#include <random>
#include <ranges>
#include <vector>
using namespace std;
istream& fin = cin;
ostream& fout = cout;
using ui = unsigned int;
using uli = unsigned long long int;
using ulli = __uint128_t;
const ui W = [] {
  random_device rd;
  return uniform_int_distribution<ui>{(ui)2e5, (ui)2e6}(rd);
}();
constexpr uli P = 1000000000000001771;
auto const H = []() {
  array<uli, (size_t)2e5 + 1> h;
  h[0] = 1;
  for (size_t i = 1; i < h.size(); ++i) h[i] = h[i - 1] * (ulli)W % P;
  return h;
}();
vector<size_t> color(size_t k, vector<vector<size_t>>& mp, size_t s = 0,
                     size_t c = 0) {
  vector<size_t> a(mp.size(), ~0);
  a[s] = c;
  queue<size_t> q{{s}};
  while (!q.empty()) {
    size_t p = q.front();
    q.pop();
    ui t = (a[p] + 1) % k;
    for (size_t i : mp[p])
      if (~a[i])
        assert(a[i] == t);
      else
        a[i] = t, q.push(i);
  }
  return a;
}
int main(void) {
  ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
  size_t T;
  fin >> T;
  while (T--) {
    size_t n, k, m0, m1;
    fin >> n >> k;
    vector<bool> a0(n), a1(n);
    vector<vector<size_t>> g0(n), g1(n);
    for (auto i : a0) {
      char c;
      fin >> c;
      i = c == '1';
    }
    fin >> m0;
    while (m0--) {
      size_t x, y;
      fin >> x >> y;
      g0[--x].emplace_back(--y);
    }
    for (auto i : a1) {
      char c;
      fin >> c;
      i = c == '1';
    }
    fin >> m1;
    while (m1--) {
      size_t x, y;
      fin >> x >> y;
      g1[--x].emplace_back(--y);
    }
    if ((count(a0.begin(), a0.end(), true) == n &&
         count(a1.begin(), a1.end(), false) == n) ||
        (count(a0.begin(), a0.end(), true) == 0 &&
         count(a1.begin(), a1.end(), false) == 0)) {
      fout << "YES\n";
      continue;
    }
    auto t0 = color(k, g0), t1 = color(k, g1);
    vector<size_t> c0i(k), c0o(k), c1i(k), c1o(k);
    for (size_t i : ranges::views::iota((size_t)0, n))
      ++(!a0[i] ? c0i : c0o)[t0[i]], ++(!a1[i] ? c1i : c1o)[t1[i]];
    uli h0i = 0, h0o = 0, h1i = 0, h1o = 0;
    for (size_t i : ranges::views::iota((size_t)0, k))
      h0i = (h0i + (ulli)c0i[i] * H[k - i - 1]) % P,
      h0o = (h0o + (ulli)c0o[i] * H[k - i - 1]) % P,
      h1i = (h1i + (ulli)c1i[i] * H[k - i - 1]) % P,
      h1o = (h1o + (ulli)c1o[i] * H[k - i - 1]) % P;
    auto shift = [k](uli v, size_t c) -> uli {
      return ((v + P - (ulli)c * H[k - 1] % P) * W + (ulli)c * H[0]) % P;
    };
    for (size_t i : ranges::views::iota((size_t)0, k)) {
      if (h0o == shift(h1i, c1i[i]) && h1o == shift(h0i, c0i[0])) {
        fout << "YES\n";
        goto end;
      }
      h1i = shift(h1i, c1i[i]), h1o = shift(h1o, c1o[i]);
    }
    fout << "NO\n";
  end:;
  }
  return 0;
}
posted @ 2024-11-07 17:03  MrPython  阅读(5)  评论(0)    收藏  举报  来源