1 条题解

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

    思路与算法

    从小到大找十进制含7且尚未标坏的整数,把它的全部倍数标坏。对超过最大询问且已找到一个可报数的有限前缀,从后向前建立下一个可报数表,回答坏数-1,否则表中后继。

    正确性说明

    若某个含7数已被更小含7因子标坏,它的倍数也已被该因子覆盖,所以跳过不会漏标。所有被标数都有含7因子,所有存在含7因子的数都会被某个最早未标因子覆盖。后向扫描保留最近的严格更大好数,查询因而正确。

    复杂度

    一次筛到B用O(B log B+B log B/ log 10+T)保守时间上界、O(B+T)空间,含标记与后继表初始化;按需扩展B时重新验证存在询问上界后的好数。

    易错点

    不只是7的倍数,17、27等的倍数也不能报;询问数本身含7直接坏。需越过最大询问找到合法后继,不把数组边界当答案。排版负号‐1按整数-1处理。

    参考代码(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 T;
        cin >> T;
        vector<int> x(T);
        int mx = 0;
        for (int &v : x) {
            cin >> v;
            mx = max(mx, v);
        }
        int N = mx + 1024;
        vector<unsigned char> bad;
        auto has7 = [](int x) {
            while (x) {
                if (x % 10 == 7)
                    return true;
                x /= 10;
            }
            return false;
        };
        while (true) {
            bad.assign(N + 1, 0);
            for (int i = 1; i <= N; i++)
                if (!bad[i] && has7(i))
                    for (int j = i; j <= N; j += i)
                        bad[j] = 1;
            bool extra = false;
            for (int i = mx + 1; i <= N; i++)
                if (!bad[i]) {
                    extra = true;
                    break;
                }
            if (extra)
                break;
            N *= 2;
        }
        vector<int> nxt(N + 1, -1);
        int last = -1;
        for (int i = N; i >= 1; i--) {
            nxt[i] = last;
            if (!bad[i])
                last = i;
        }
        for (int v : x)
            cout << (bad[v] ? -1 : nxt[v]) << "\n";
    }
    
    • 1

    信息

    ID
    1962
    时间
    1000ms
    内存
    512MiB
    难度
    普及
    标签
    递交数
    0
    已通过
    0
    上传者