1 条题解

  • 0
    @ 2026-10-27 0:36:27

    思路与算法

    从每个观测状态反向枚举45种单圈非零偏移与36种相邻双圈相同非零偏移,用集合求全部状态的候选正确密码交集。

    正确性说明

    拨圈操作模10可逆,非零偏移的逆仍在1..9,反向枚举恰得到能产生该状态的全部正确密码。对所有观测取交集等价同时能产生全部状态,去重集合计数正是答案。

    复杂度

    O(81n log81)时间、O(81+n)空间,含状态输入和每次候选集合初始化;n<=8。

    易错点

    两圈必须相邻且偏移相同;只转一圈不能允许0幅度,五位中的首位0仍是有效数字,不可丢失位数。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    struct DS {
        vector<int> p, s;
        DS(int n) : p(n), s(n, 1) {
            iota(p.begin(), p.end(), 0);
        }
        int find(int u) {
            while (p[u] != u) {
                p[u] = p[p[u]];
                u = p[u];
            }
            return u;
        }
        bool join(int a, int b) {
            a = find(a);
            b = find(b);
            if (a == b)
                return false;
            if (s[a] > s[b])
                swap(a, b);
            p[a] = b;
            s[b] += s[a];
            return true;
        }
    };
    
    int main() {
        int n;
        cin >> n;
        vector<array<int, 5>> a(n);
        for (auto &v : a)
            for (int &x : v)
                cin >> x;
        set<int> good;
        for (int t = 0; t < n; t++) {
            set<int> cur;
            for (int i = 0; i < 5; i++)
                for (int z = 1; z < 10; z++) {
                    auto v = a[t];
                    v[i] = (v[i] + z) % 10;
                    int code = 0;
                    for (int x : v)
                        code = code * 10 + x;
                    cur.insert(code);
                    if (i < 4) {
                        v[i + 1] = (v[i + 1] + z) % 10;
                        code = 0;
                        for (int x : v)
                            code = code * 10 + x;
                        cur.insert(code);
                    }
                }
            if (t == 0)
                good = cur;
            else {
                set<int> out;
                set_intersection(good.begin(), good.end(), cur.begin(), cur.end(),
                                 inserter(out, out.begin()));
                good.swap(out);
            }
        }
        cout << good.size() << "\n";
    }
    
    • 1

    信息

    ID
    1963
    时间
    1000ms
    内存
    512MiB
    难度
    进阶
    标签
    递交数
    0
    已通过
    0
    上传者