WC2026 T1
Register_int · · 题解
没有人类了。
由于数据量极大,下文讨论中认为 __builtin_popcount 函数的时间复杂度为
\mathcal{O}(T\log V\log\log V)
不难发现你给
- 倍增了
t 次,2^t x>y 。此时操作次数为t+2^tx-y 。 - 倍增了
t 次,2^t x\le y ,还需要补上k=y-2^t 。
显然第一类要选尽可能小的 __lg 算。问题在于,在第二类操作中,答案并不是简单的
直接枚举
\mathcal{O}(\log V\log\log V+T\log\log V)
不妨再将
- 我们的目标比较长远,要把很长一段
1 填平。这个时候把最低6 位直接填平一定是不劣的。 - 没那么多
1 让我们消,那么我们只关心最后6 位内的情况。这部分可以预处理出对应的答案。
第一类直接位运算解决,第二类提取低六位查表即可。期望得分
#include <bits/stdc++.h>
#include "binary.h"
using namespace std;
typedef long long ll;
int f[64], pc[70];
void init(int c, int t) {
for (int i = 0; i < 70; i++) pc[i] = __builtin_popcount(i);
for (int i = 0; i < 64; i++) {
for (int j = 0; j < 6; j++) f[i] = max(f[i], pc[i] - pc[i + j] - j);
}
}
inline
int calc(ll x) {
if (!x) return 0; ll y = (x | 63) + 1;
return min<int>(__builtin_popcountll(y) + y - x, __builtin_popcountll(x) - f[x & 63]);
}
ll binary(ll x, ll y) {
int cnt = __lg(y) - __lg(x); x <<= cnt; if (x > y) x >>= 1, cnt--;
return cnt + min<ll>((x << 1) - y + 1, (y - x >> cnt) + calc(y - x & (1ll << cnt) - 1));
}
Bonus:\mathcal{O}(\sqrt[3]V+\log V\log\log V+T)
额就是你打表一下 popcount,就这样。但是寻址三次和 popcount 哪个快我确实不好说。这个可以做到理论最优就是了。
#include <bits/stdc++.h>
#include "binary.h"
using namespace std;
typedef long long ll;
const int B = 1 << 21;
int f[64], pc[1 << 21];
void init(int c, int t) {
for (int i = 1; i < B; i++) pc[i] = pc[i & i - 1] + 1;
for (int i = 0; i < 64; i++) {
for (int j = 0; j < 6; j++) f[i] = max(f[i], pc[i] - pc[i + j] - j);
}
}
inline int popcount(ll x) { return pc[x & B - 1] + pc[x >> 21 & B - 1] + pc[x >> 42 & B - 1]; }
inline
int calc(ll x) {
if (!x) return 0; ll y = (x | 63) + 1;
return min<int>(popcount(y) + y - x, popcount(x) - f[x & 63]);
}
ll binary(ll x, ll y) {
int cnt = __lg(y) - __lg(x); x <<= cnt; if (x > y) x >>= 1, cnt--;
return cnt + min<ll>((x << 1) - y + 1, (y - x >> cnt) + calc(y - x & (1ll << cnt) - 1));
}