1 条题解
-
0
自动搬运
来自洛谷,原作者为

花淇淋
物极必反。搬运于
2025-08-24 22:09:46,当前版本为作者最后更新于2019-05-12 15:35:54,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Address
Solution
- 对于 ,由于路径长度为 级别,只要知道 就是 二进制下的 就可以做了。
- 对于 ,先和 一样求出路径编号和,然后要知道一个显然性质和一个神仙性质: 记 二进制中 的个数为 ,则 到根的路径编号和为 。注意这个性质在根为 时也成立,只要 的儿子还是 。 记路径的编号和为 ,路径的两个端点为 ,, 要经过 条边, 要经过 条边。那么当 都为定值时, 也必为定值。
- 考虑证明性质 把路径 上的每个点编号写成二进制,它们的 就是 的二进制。记 的二进制有 位,那么先算出每个点编号前 位的值的贡献。 的贡献是 , 的每个儿子的贡献是 ,每个孙子的贡献是 ,依此类推,可以得出前 位的总贡献 为:
- 记 为其它贡献,即: 讨论 的取值范围(先假设 ): 往左走 步,然后往左走 步到 ; 往右走 步,然后往左走 步到 。路径 对 的贡献为 , 对 的贡献为 ,此时 取最小值。 往左走 步,然后往右走 步到 ; 往右走 步,然后往右走 步到 。路径 对 的贡献为 , 对 的贡献为 ,此时 取最大值。 综上所述,。
- 发现 ,那么 , 的值只和 有关,所以 为定值,证毕。
- 那么问题转化为:找到两个数 (就是 砍掉前 位之后的值,砍掉前 位后,最高位是 , 最高位是 ),,注意 的 位必须为 。
- 枚举 ,得到 ,做数位, 表示从个位开始( 同时填),填了 位,此时共填 个 ,是否进位到第 位,要求 的每一位都和 对上即可。
注意细节,注意多开 ,注意树高对 值的限制。- 时间复杂度 ,常数显然很小。
Code
#include <bits/stdc++.h> using namespace std; #define ll long long template <class t> inline void read(t & res) { char ch; while (ch = getchar(), !isdigit(ch)); res = ch ^ 48; while (ch = getchar(), isdigit(ch)) res = res * 10 + (ch ^ 48); } template <class t> inline void print(t x) { if (x > 9) print(x / 10); putchar(x % 10 + 48); } const int e = 205; ll f[e][e][2], ans; bool a1[e], b1[e]; inline ll dp(int a, int b, ll s, int c) { int i, j, t, x, y, bit = max(max(a - 1, b), (int)log2(s) + 1) + 1; bool flag = a == 3 && b == 2; for (i = 0; i < bit; i++) for (j = 0; j <= c; j++) f[i][j][0] = f[i][j][1] = 0; i = 0; for (x = 0; x <= 1; x++) for (y = 0; y <= 1; y++) { int k = x + y >> 1, z = x + y & 1; if (i == b - 1 && !y) continue; if (z != (s & 1)) continue; if (i > b - 1 && y) continue; if (i > a - 2 && x) continue; f[0][x + y][k]++; } for (i = 0; i < bit - 1; i++) { ll d = s & (1ll << i + 1); if (d) d = 1; for (j = 0; j <= c; j++) for (t = 0; t <= 1; t++) if (f[i][j][t]) for (x = 0; x <= 1; x++) for (y = 0; y <= 1; y++) { int now = x + y + t, k = now >> 1, z = now & 1; if (i + 1 == b - 1 && !y) continue; if (z != d) continue; if (i + 1 > b - 1 && y) continue; if (i + 1 > a - 2 && x) continue; f[i + 1][j + x + y][k] += f[i][j][t]; } } return f[bit - 1][c][0]; } inline ll calc(ll x) { ll res = x << 1; while (x) res -= x & 1, x >>= 1; return res; } int main() { int i, lx, ly, op, tst, h; ll x, y, z; read(tst); while (tst--) { read(h); read(x); read(y); read(op); ll x2 = x, y2 = y; lx = ly = z = 0; while (x) a1[++lx] = x & 1, x >>= 1; while (y) b1[++ly] = y & 1, y >>= 1; reverse(a1 + 1, a1 + lx + 1); reverse(b1 + 1, b1 + ly + 1); for (i = 1; i <= lx && i <= ly; i++) if (a1[i] == b1[i]) z = z * 2 + a1[i]; else break; ll s = calc(x2) + calc(y2) - calc(z) - calc(z >> 1); if (op == 1) { print(s); putchar('\n'); continue; } ans = 0; for (int a = 0; a < h; a++) for (int b = 0; b < h; b++) { ll y = ((1ll << a + 1) + (1ll << b + 1) - 3), x = s / y; if (!x) continue; if ((int)log2(x) + 1 + max(a, b) > h) continue; ll k = s - x * y; for (int c = 0; c <= a + b; c++) if ((k + c) % 2 == 0) ans += dp(a, b, k + c >> 1, c); } print(ans - 1); putchar('\n'); } return 0; } ll k = s - x * y; for (int c = 0; c <= a + b; c++) if ((k + c) % 2 == 0) ans += dp(a, b, k + c >> 1, c); } print(ans - 1); putchar('\n'); } return 0; }
- 1
信息
- ID
- 4336
- 时间
- 4000ms
- 内存
- 125MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者