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\)),根据这些关系并特判符合上述某条件之一优化差卷积,可以通过更多点。

posted @ 2026-05-05 19:48  hhoppitree  阅读(50)  评论(0)    收藏  举报