[Algo Beat Contest 001 E] Experiments on Collatz 官方题解
出题人确实对角谷猜想很感兴趣呢。希望总有一天这个数学谜题被解开。
Part 1 - 预处理函数值
首先,可以很容易用递归暴力一一求解出所有的函数值,但是这样的效率显然很低,因为相同的函数值可能会在求解过程中被计算多次。
于是考虑记忆化剪枝优化。对于小于等于
以上可以在一秒内处理。
Part 2 - 第一种询问
这个非常简单啦,直接进行预处理即可。
Part 3 - 第二种询问
这个可以考虑预处理前缀积,令
Part 4 - Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int q, dp[10000005], ans[10000005];
ll pre[10000005], mn = 2e9;
const int mod = 1145141923;
ll qp(ll x, ll y) {
if (y == 0) {
return 1;
}
ll res = qp(x, y / 2);
res *= res;
res %= mod;
if (y % 2) {
res *= x;
res %= mod;
}
return res;
}
int f(long long x) {
if (x == 1) {
return dp[x] = 0;
}
if (x <= 10000000 && dp[x]) {
return dp[x];
}
if (x % 2 == 0) {
ll res = f(x / 2) + 1;
if (x <= 10000000) {
dp[x] = res;
}
return res;
} else {
ll res = f(x * 3 + 1) + 1;
if (x <= 10000000) {
dp[x] = res;
}
return res;
}
}
int inv(int x) {
return qp(x, mod - 2);
}
int main() {
ans[0] = 1;
pre[0] = pre[1] = 1;
for (int i = 1; i <= 10000001; i++) {
dp[i] = f(i);
ans[i] = 2e9;
if (i != 1) {
pre[i] = pre[i - 1] * dp[i];
pre[i] %= mod;
}
}
for (int i = 1; i <= 10000000; i++) {
ans[dp[i]] = min(ans[dp[i]], i);
}
for (int i = 10000000; i >= 0; i--) {
ans[i] = min(ans[i], ans[i + 1]);
}
cin >> q;
for (int i = 1, t, x, y; i <= q; i++) {
cin >> t;
if (t == 1) {
cin >> x;
cout << ans[x] << endl;
} else {
cin >> x >> y;
if (x == 1) {
cout << 0 << endl;
} else {
cout << pre[y] * inv(pre[x - 1]) % mod << endl;
}
}
}
return 0;
}