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";
}
本文来自博客园,作者:CuteNess,转载请注明原文链接:https://www.cnblogs.com/CuteNess/p/22533978

浙公网安备 33010602011771号