qoj8564 Three Vectors

给你 \(3\) 个长为 \(n\)互不相同的 01 向量 \(s_i\),要求构造一个 2-SAT \(T\) 使得:

  • \(\forall i,s_i\)\(T\) 的一个解。
  • \(T\) 的解数量尽可能少。
  • \(|T|\le2n\)

\(c_j\) 表示 \(3\) 个串中第 \(j\) 位为 \(1\) 的个数。这里有 \(0\le c_j\le 3\)

通过对位 \(j\)\(3\) 个串上同时翻转可以做到 \(c_j\leftarrow\min(c_j,3-c_j)\le 1\)

此时考虑每一位 \(j\)\(3\) 个串上的状态 \((s_{0,j}, s_{1,j}, s_{2,j})\) 只有 \(4\) 种可能。

可以通过条件 \((\neg x\lor y)\land(x\lor\neg y)\) 迫使 \(x,y\) 取值相同。

即可归约到 \(n=4\) 的问题,每个删去的位使用 \(2\) 个条件。

对于状态 \((0,0,0)\),可以用 \(\neg x\lor\neg x\) 钦定。

对于剩下的 \(3\) 种状态,取其对应的 \(3\) 个位 \(x,y,z\),利用 \(\neg x\lor\neg y\),可以钦定 \(x,y\) 不全为 \(1\)

那么取其轮换可以迫使 \((s_x,s_y,s_z)\) 取得 \(000/001/010/100\) 之一。

可以证明无论如何 \((x,y,z)=000\) 时总为一解。考虑由 \(c_i\le 1\)\(\forall j,k,\exist i\ \mathrm{s.t.}\ s_{i,j}=s_{i,k}=0\)

总条件数恰好为 \(2n\)


#include <iostream>
#include <vector>

int main() {
  int n; std::cin >> n;
  std::vector<std::string> s(3);
  std::cin >> s[0] >> s[1] >> s[2];
  std::vector<int> rev(n);
  for(int i = 0; i < n; ++i) {
    int cnt = 0;
    for(int j = 0; j < 3; ++j)
      cnt += s[j][i] == '1';
    if(cnt > 1) {
      cnt = 3 - cnt;
      rev[i] = 1;
      for(int j = 0; j < 3; ++j)
        s[j][i] ^= 1;
    }
  }
  std::vector<std::pair<int, int>> ans;
  auto reg = [&](int x, int y) {
    if(rev[std::abs(x)-1]) x = -x;
    if(rev[std::abs(y)-1]) y = -y;
    ans.emplace_back(x, y);
  };
  std::vector<int> las(4), fir(4, -1);
  for(int i = 0; i < n; ++i) {
    int t = 3;
    for(int j = 0; j < 3; ++j)
      if(s[j][i] == '1') t = j;
    if(~fir[t]) {
      int k = las[t]; las[t] = i;
      reg(i+1, -(k+1));
      reg(k+1, -(i+1));
    } else {
      fir[t] = las[t] = i;
    }
  }
  if(~fir[3]) {
    reg(-fir[3]-1, -fir[3]-1);
  }
  for(int i = 0; i < 3; ++i) {
    for(int j = 0; j < i; ++j) {
      if(~fir[i] && ~fir[j]) {
        reg(-fir[i]-1, -fir[j]-1);
      }
    }
  }
  std::cout << ans.size() << "\n";
  for(auto& [x, y]: ans)
    std::cout << x << ' ' << y << "\n";
}
posted @ 2026-08-18 04:07  CuteNess  阅读(6)  评论(0)    收藏  举报