题解:P8350 [SDOI/SXOI2022] 进制转换
是个美难题。
第一个想法是假设
我尝试设
设
但是这样跑起来比二进制还慢。但是我们注意到关于这种进制数位的题,随便优化一个个位置就是指数级别的优化。我们发现对于
不太熟这种 trick 的人可能有点难以理解,实际上就是将原本的
转移可以根据我们钦定的进位,和加的值以及后继状态是否钦定进位去算固定的转移系数。相当于是说,首先枚举当前位是几,然后枚举后继是否进位,看加起来后看当前能否进位,也就是加起来的数是否
但是这样没做完,我们忙活半天这个复杂度还是劣完了。我们不难感受到
这题还有一些其它做法,总之都是利用了位的贡献可拆然后去搞类似分治的东西,这是一个很好的思想。
代码:
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i (l); i <= (r); ++ i)
#define rrp(i, l, r) for (int i (r); i >= (l); -- i)
#define eb emplace_back
using namespace std;
#define pii pair <int, int>
#define inf 1000000000ll
#define ls (p << 1)
#define rs (ls | 1)
#define fi first
#define se second
constexpr int N = 1e7 + 5, M = 60 + 5, P = 998244353;
typedef long long ll;
typedef unsigned long long ull;
inline ll rd () {
ll x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) {
if (ch == '-') f = -1;
ch = getchar ();
}
while (isdigit (ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar ();
}
return x * f;
}
int qpow (int x, int y) {
int ret (1);
for (; y; y >>= 1, x = x * x % P) if (y & 1) ret = ret * x % P;
return ret;
}
int t[N], * o, * f[13][2];
ll ef[M], py[M], p3[M], n, x, y, z;
ll pw[M];
int m;
int dfs (int step, ll now, bool go, bool up) {
if (step == -1) return ! go;
if (step <= 12 && ! up && f[step][go][now] > -1) return f[step][go][now];
ll ret (0);
int lim = up ? (n / p3[step] % 3) : 2;
ll cur (1);
rep (i, 0, lim) {
if (i > 0) cur = cur * pw[step] % P * z % P;
ll tmp (now + p3[step] * i);
rep (j, 0, 1) {
ll val (step ? ef[step - 1] : 1);
ll nxt (tmp + j * val);
if ((nxt >= ef[step]) == go) {
nxt -= ef[step] * go;
ret += py[__builtin_popcountll (nxt / val)] * cur % P * dfs (step - 1, nxt % val, j, up & (i == lim));
}
}
}
ret %= P;
if (step <= 12 && ! up) f[step][go][now] = ret;
return ret;
}
int32_t main () {
n = rd (), x = rd (), y = rd (), z = rd ();
p3[0] = 1, py[0] = 1;
ll c (1);
while (c <= n) c *= 3, ++ m;
pw[0] = x;
rep (i, 1, m) p3[i] = p3[i - 1] * 3, pw[i] = pw[i - 1] * pw[i - 1] % P * pw[i - 1] % P;
rep (i, 1, M - 1) py[i] = py[i - 1] * y % P;
o = t;
rep (i, 0, m) {
ef[i] = 1ll << (int) ceil (log2 (3) * (i + 1));
if (i <= 12) {
f[i][0] = o, o += ef[i], f[i][1] = o, o += ef[i];
rep (j, 0, ef[i] - 1) f[i][0][j] = f[i][1][j] = -1;
}
}
cout << (dfs (m, 0, 0, 1) - 1 + P) % P;
}