Bombe 通关记录
默认已经解锁所有内容。
首先,我们先考虑减少约束的种类。
- \(= x\) 的限制可以拆成 \(\ge x\) 和 \(\le x\);
- \(x\operatorname{or}\;(x+1)\) 可以拆成 \(\ge x\) 和 \(\le x+1\);
- \(x\operatorname{or}\;(x+2)\) 可以拆成 \(\ge x\) 和 \(\le x+2\) 和 \(\ne x+1\);
- \(x\operatorname{or}\;(x+3)\) 可以拆成 \(\ge x\) 和 \(\le x+3\) 和 \(\ne x+1\) 和 \(\ne x+2\);
- \(x\operatorname{or}\;(x+1)\operatorname{or}\;(x+2)\) 可以拆成 \(\ge x\) 和 \(\le x+2\);
- \(x\operatorname{or}\;(x+2)\operatorname{or}\;(x+4)\) 可以拆成 \(\ge x\) 和 \(\le x+4\) 和 \(\ne x+1\) 和 \(\ne x+3\);
- \(x+2\times\) 可以拆成 \(\ge x\) 和「\(2\times\) 或 \(1+2\times\)」。
下记条件 \(E\) 为 \(2\times\),即为偶数;记条件 \(O\) 为 \(1+2\times\),即为偶数。
总而言之,我们将所有的运算拆成了 \(\ne x,\le x,\ge x,E,O\) 五种条件。
自然地,一个区域的雷数在 \([0,S]\) 之间,其中 \(S\) 为区域大小。
考虑二线索之间的推理,可以将这视作是两个区域交集雷数的取交,由于上一行,我们只需实现条件的差卷积和取交。
先考虑取交,由于两个 \(\le\) 和两个 \(\ge\) 之间都可以直接删除,同时 \(\le x\) 可以和 \(\ne x\) 取交,\(\ge x\) 可以和 \(\ne x\) 取交,如果 \(\ge x\) 并且 \(x\) 与 \(E/O\) 不符可以 \(x\to x+1\),如果 \(\le x\) 并且 \(x\) 与 \(E/O\) 不符可以 \(x\to x-1\),如果一个 \(\ne x\) 中 \(x\) 本来就不符合条件可以删去。
处理后,所以限制都可以表示为 \(([L,R],E/O/\varnothing,\{\})\) 的三元组,分别表示范围 / 奇偶性限制 / 不允许的数,并且范围两端点均符合条件,不允许的数均符合奇偶性和大小限制。
差卷积仅使用奇偶性和上下限计算,这样明显是错的,但是能过很多题目,生成错误情况代码:
#include <vector>
#include <algorithm>
#include <cassert>
#define MAX_NUMBER 9
bool checkInRange(int number, int L, int R) {
return number >= L && number <= R;
}
bool checkParity(int number, int parity) {
if (parity == -1) return true;
if (number % 2 == parity) return true;
return false;
}
bool checkNotDel(int number, std::vector<int> del) {
if (std::find(del.begin(), del.end(), number) != del.end()) return false;
return true;
}
struct ValidNumber {
std::vector<int> nums;
ValidNumber() {
nums.clear();
}
void clear() {
nums.clear();
}
void setAll() {
for (int i = 0; i <= MAX_NUMBER; i++) {
nums.push_back(i);
}
}
void simplify() {
std::sort(nums.begin(), nums.end());
nums.erase(std::unique(nums.begin(), nums.end()), nums.end());
}
ValidNumber friend Union(ValidNumber x, ValidNumber y) {
std::sort(x.nums.begin(), x.nums.end());
std::sort(y.nums.begin(), y.nums.end());
ValidNumber result;
result.clear();
std::set_union(x.nums.begin(), x.nums.end(), y.nums.begin(), y.nums.end(), std::back_inserter(result.nums));
return result;
}
ValidNumber friend operator - (ValidNumber x, ValidNumber y) {
ValidNumber result;
result.clear();
for (auto i : x.nums) {
for (auto j : y.nums) {
if (i >= j) result.nums.push_back(i - j);
}
}
result.simplify();
return result;
}
};
struct Restriction {
int L, R, parity;
std::vector<int> del;
Restriction() {
L = 0, R = MAX_NUMBER, parity = -1, del.clear();
}
void simplify() {
while (L <= R && (!checkParity(L, parity) || !checkNotDel(L, del))) L++;
while (L <= R && (!checkParity(R, parity) || !checkNotDel(R, del))) R--;
assert(L <= R);
std::sort(del.begin(), del.end());
del.erase(std::unique(del.begin(), del.end()), del.end());
std::vector<int> cur = del;
del.clear();
for (auto x : cur) {
if (checkInRange(x, L, R) && checkParity(x, parity)) {
del.push_back(x);
}
}
}
ValidNumber toValidNumber() {
std::vector<int> nums;
for (int i = 0; i <= MAX_NUMBER; i++) {
if (checkInRange(i, L, R) && checkParity(i, parity) && checkNotDel(i, del)) {
nums.push_back(i);
}
}
ValidNumber result;
result.nums = nums;
return result;
}
void print() {
printf("L: %d\nR: %d\nParity: %d\n", L, R, parity);
printf("Del: ");
for (int i = 0; i < (int)del.size(); i++) {
printf("%d", del[i]);
if (i + 1 != (int)del.size()) printf(" ");
}
printf("\n");
}
Restriction friend Union(Restriction x, Restriction y) {
return Restriction();
}
Restriction friend operator - (Restriction x, Restriction y) {
Restriction result;
result.L = x.L - y.R, result.R = x.R - y.L;
if (x.parity != -1 && y.parity != -1) {
result.parity = x.parity ^ y.parity;
}
return result;
}
};
#include <vector>
#include <iostream>
#include "Restriction.hpp"
std::vector<Restriction> genAllRestrictions() {
std::vector<Restriction> result;
for (int L = 0; L <= MAX_NUMBER; L++) {
for (int R = L; R <= MAX_NUMBER; R++) {
for (int parity : {-1, 0, 1}) {
if (!checkParity(L, parity) || !checkParity(R, parity)) continue;
std::vector<int> values;
for (int w = L + 1; w <= R - 1; w++) {
if (checkParity(w, parity)) values.push_back(w);
}
for (int i = 0; i < (1 << (int)values.size()); i++) {
std::vector<int> sub;
for (int j = 0; j < (int)values.size(); j++) {
if ((i >> j) & 1) sub.push_back(values[j]);
}
Restriction rest;
rest.L = L, rest.R = R, rest.parity = parity, rest.del = sub;
result.push_back(rest);
}
}
}
}
return result;
}
int main() {
std::vector<Restriction> rest = genAllRestrictions();
int ID = 0, cnt = 0;
for (auto x : rest) {
for (auto y : rest) {
cnt++;
ValidNumber myUnion = (x - y).toValidNumber(),
realUnion = x.toValidNumber() - y.toValidNumber();
if (myUnion.nums != realUnion.nums) {
printf("# %4d:\n\n", ID++);
x.print(), printf("\n----------\n"), y.print();
printf("\n");
}
}
}
printf("WRONG NUMBERS: %d / %d\n", ID, cnt);
return 0;
}
同时可以反推(例如 \(\ge x,\le x\Rightarrow =x\)),根据这些关系并特判符合上述某条件之一优化差卷积,可以通过更多点。

浙公网安备 33010602011771号