hdu1001 TLE部分思路

优雅集合与最小答案求解

题意回顾

给定一个优雅集合 $S$ 满足:

  • $0,, 2^{64}-1 \in S$;
  • 对任意 $u,v\in S$,有 $u&v\in S$ 且 $u,|,v\in S$。

现在已知 $S$ 中的 $n$ 个元素(记为集合 $A$),对于每个查询给定一个自然数 $x$,要求求出最小的自然数 $y\ge x$,使得 $y$ 一定在 $S$ 中。


思路说明

我们可以证明,对于任意优雅集合 $S$,由已知集合 $A$ 可以推出每一位上的“必然取值”。具体做法如下:

  1. 预处理“必然值”

    对于每个二进制位 $b$($0\le b<64$),令

    \[\texttt{bit}[b] = \bigwedge\{\,a : a\in A \text{ 且 }a\text{的第 }b\text{位为 }1\}, \]

    如果没有已知数在该位为 $1$,则令 $\texttt{bit}[b]=2^{64}-1$。

    可以证明:对于任意 $y\in S$,如果 $y$ 的第 $b$ 位为 $1$,则必须有

    \[y\&\texttt{bit}[b]=\texttt{bit}[b]. \]

  2. 问题转化

    对于任意查询给定 $x$,问题转化为求满足下列条件的最小 $y$:

    1. $y\ge x$;
    2. 对于所有 $0\le b<64$,若 $y$ 的第 $b$ 位为 $1$,则有

      \[y\&\texttt{bit}[b]=\texttt{bit}[b]. \]

    在满足上述条件的 $y$ 中取最小值。

  3. 构造候选答案

    如果 $x$ 本身满足条件,则答案即为 $x$。否则,我们枚举 $i=0,1,\dots,63$ 构造候选答案:

    \[y_i=\left(\left\lfloor\frac{x}{2^{i+1}}\right\rfloor\times2^{i+1}\right)\,|\,\texttt{bit}[i], \]

    即保留 $x$ 高于低 $i+1$ 位的部分,然后低位统一填上由 $\texttt{bit}[i]$ 给出的模式。
    在所有满足 $y_i\ge x$ 且满足条件的候选中,取最小者。


完整 C++ 代码

下面给出完整代码,其中用内联函数 valid(y, bitArr) 判断 $y$ 是否满足“必然性条件”,并对每个查询构造候选答案,最后将答案取模后异或输出。

#include <bits/stdc++.h>
using namespace std;
 
// 模数 M = 10^16 + 1029
const unsigned long long M = 10000000000000000ULL + 1029ULL;
 
// 检查 y 是否满足:对于每个 b (0<=b<64),若 y 的第 b 位为 1,则必须有 (y & bitArr[b]) == bitArr[b]。
inline bool valid(unsigned long long y, const unsigned long long bitArr[64]) {
    for (int b = 0; b < 64; b++) {
        if ((y >> b) & 1ULL) {
            if ((y & bitArr[b]) != bitArr[b])
                return false;
        }
    }
    return true;
}
 
// 快速读取 unsigned long long(可根据需要调整)
static inline bool scanULL(unsigned long long &x) {
    int c = getchar();
    if(c == EOF) return false;
    while(c != EOF && (c==' ' || c=='\n')) c = getchar();
    if(c == EOF) return false;
    x = 0;
    while(c != EOF && c >= '0' && c <= '9'){
        x = x * 10ULL + (unsigned long long)(c - '0');
        c = getchar();
    }
    return true;
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int T;
    cin >> T;
    while(T--){
        int n, q;
        cin >> n >> q;
        vector<unsigned long long> a(n);
        for (int i = 0; i < n; i++){
            cin >> a[i];
        }
        // 预处理 bitArr[0..63],初始化为全 1,即 2^64 - 1
        unsigned long long bitArr[64];
        for (int b = 0; b < 64; b++){
            bitArr[b] = ~0ULL;
        }
        // 对每个 a,如果 a 的第 b 位为1,则 bitArr[b] &= a
        for (int i = 0; i < n; i++){
            for (int b = 0; b < 64; b++){
                if ((a[i] >> b) & 1ULL)
                    bitArr[b] &= a[i];
            }
        }
 
        unsigned long long xorAns = 0;
        // 对每个查询,求最小 y >= x 且 y 必定在 S 中
        for (int qi = 0; qi < q; qi++){
            unsigned long long x;
            cin >> x;
            unsigned long long best = ~0ULL; // 初始化为 2^64 - 1
            // 如果 x 本身满足条件,则候选答案可以为 x
            if (valid(x, bitArr))
                best = x;
            // 枚举 i = 0 .. 63 构造候选答案
            for (int i = 0; i < 64; i++){
                // 舍去低 i+1 位:右移后再左移
                unsigned long long prefix = (x >> (i+1)) << (i+1);
                unsigned long long cand = prefix | bitArr[i];
                if (cand >= x && valid(cand, bitArr))
                    best = min(best, cand);
            }
            // 将答案取模后异或累积
            unsigned long long modAns = best % M;
            xorAns ^= modAns;
        }
        cout << xorAns << "\n";
    }
    return 0;
}

代码说明

  1. 预处理部分

    用长度为 64 的数组 bitArr 保存每一位的“必然值”,初始化为全 1(即 $2^{64}-1$)。对于每个已知的 $a\in A$,如果其第 $b$ 位为 1,则更新:

    \[\texttt{bitArr}[b] \,\&=\, a. \]

    若某一位从未出现过 1,则保持为全 1。

  2. 合法性判断

    函数 valid(y, bitArr) 对 $y$ 的每一位进行检查:若 $y$ 的第 $b$ 位为 1,则必须满足

    \[y\&\texttt{bitArr}[b]=\texttt{bitArr}[b]. \]

  3. 构造候选答案

    对于每个查询给定 $x$,先检查 $x$ 是否满足条件,若满足则答案为 $x$。否则,枚举 $i=0,\dots,63$ 构造候选答案:

    \[y_i=\left(\left\lfloor\frac{x}{2^{i+1}}\right\rfloor \times2^{i+1}\right) \,|\, \texttt{bitArr}[i]. \]

    在所有满足 $y_i\ge x$ 且合法的候选中取最小者。

  4. 答案输出

    每组测试中,将所有查询的答案取模 $M = 10^{16} + 1029$ 后,再将这些模值依次异或输出。

posted @ 2025-03-14 22:15  archer2333  阅读(14)  评论(0)    收藏  举报