第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
*/
浙公网安备 33010602011771号