第40次CSP认证 第2题 数字变换(transform)题解

题目链接:https://mp.weixin.qq.com/s/TVSCnnUnf2mj_Ka4ZWS1Ag

解题思路:

这题的突破口是:虽然 \(n\) 很大,但是 \(a_i\) 的范围只有在 \([0, 2^9)\),也就是说,\(n\) 次询问中肯定存在很多重复的 \(a_i\)

所以我们可以先预处理把所有结果都算出来。

本题虽然 \(n\) 很大,但是数字范围(\([0, 2^9)\))和 \(m\) 都比较小。

由于 \(x \in [0, 2^9)\)\(k \in [0, 2^3)\),所以这部分处理的时间复杂度为 \(O(xk) = O(2^{12})\)

然后我们枚举每一个初始的值 \(x \in [0, 2^9)\),令 \(x = f_0\)(初始值),然后循环 \(k\) 轮,其中第 \(i\) 轮令 \(x \leftarrow g(x, k_i)\)

这样,放 \(m\) 轮结束之后,此时的 \(x\) 就是初始的 \(f_0\) 对应的结果。

也就是说:

  • 如果结果为 \(x\),则初始值为 \(f_0\)

因为就那么 \(2^9\) 个不同的 \(f_0\),暴力计算每个 \(f_0\) 对应的结果 \(x\) 只需要循环 \(m\) 次就行。所以这部分的时间复杂度为 \(O(x m) = O(2^9 \cdot 1000)\)

我们需要额外记录一个一维数组 \(ans_x\) 表示每个结果对应的初始值是多少,即令 \(ans_x = f_0\)

然后对于 \(n\) 次询问,每次询问(因为我们都记录完答案了,所以)时间复杂度为 \(O(1)\)。那么,\(n\) 次询问的时间复杂度为 \(O(n)\)

所以,总的时间复杂度为

  • 预处理的时间 \(O(xk)\) + 枚举并得到每个答案的时间 \(O(x m)\) + 回答每个答案的时间 \(O(n)\)

其中 \(x\)\(2^9\)\(k\)\(2^3\),每一部分时间复杂度都不是很高。可以通过本题。

示例程序:

#include <bits/stdc++.h>
using namespace std;

int f(int x, int k) {
    return ( (x * x + k * k) & 7 ) ^ k;
}

int g(int x, int k) {
    int c = x & 7, b = (x >> 3) & 7, a = x >> 6;
    int aa = b, bb = c ^ f(b, k), cc = a ^ f(c, k);
    return cc | (bb << 3) | (aa << 6);
}

int ans[1<<9], n, m, k[1005];

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
        cin >> k[i];
    for (int i = 0; i < (1<<9); i++) {
        int x = i;
        for (int j = 1; j <= m; j++)
            x = g(x, k[j]);
        ans[x] = i; // 结果x对应的初始的值为i
    }
    for (int i = 0, a; i < n; i++) {
        cin >> a;
        cout << ans[a] << endl;
    }
    return 0;
}
/**
1 2
3 5
504
*/
posted @ 2025-12-08 13:11  quanjun  阅读(58)  评论(0)    收藏  举报