Address
Solution
- 挺有意思的题。
- 第一问就是暴力在树上跳,设答案为 s s s。
- 考虑第二问,单点的情况直接处理,设路径上深度最小的点为 x x x,先从简单的情况入手。
- 对于从 x x x 往下走形成的长度为 h ( h > 1 ) h(h > 1) h(h>1) 的链,如果往下走的过程中都是往左孩子走,链的编号总和为 ∑ i = 0 h − 1 2 i x = ( 2 h − 1 ) x \sum \limits_{i = 0}^{h - 1}2^ix = (2^h - 1)x i=0∑h−12ix=(2h−1)x。
- 考虑把某一步改为往右孩子走,不难发现每个右孩子的贡献是独立的。把走到倒数第 i i i 个节点的那一步改为往右孩子走产生的贡献为 ∑ j = 0 i − 1 2 j = 2 i − 1 \sum \limits_{j = 0}^{i - 1}2^j = 2^i - 1 j=0∑i−12j=2i−1。
- 一个非常关键的结论:
当 s , h s,h s,h 已知时,若存在合法的 x x x, x x x 为定值 ⌊ s 2 h − 1 ⌋ \begin{aligned} \lfloor \frac{s}{2^h - 1}\rfloor \end{aligned} ⌊2h−1s⌋。
- 证明:
- 显然有 x ≤ ⌊ s 2 h − 1 ⌋ \begin{aligned} x \le \lfloor \frac{s}{2^h - 1} \rfloor \end{aligned} x≤⌊2h−1s⌋。
- 若 x = ⌊ s 2 h − 1 ⌋ − 1 \begin{aligned} x = \lfloor \frac{s}{2^h - 1} \rfloor - 1 \end{aligned} x=⌊2h−1s⌋−1,全往右儿子走的编号和为
s ′ = ( 2 h − 1 ) ( ⌊ s 2 h − 1 ⌋ − 1 ) + ∑ i = 1 h − 1 ( 2 i − 1 ) = ( 2 h − 1 ) ⌊ s 2 h − 1 ⌋ − h < s \begin{aligned} s' &= (2^{h} - 1)( \lfloor \frac{s}{2^{h} - 1} \rfloor - 1) + \sum \limits_{i = 1}^{h - 1}{(2^i - 1)}\\ &= (2^h - 1) \lfloor \frac{s}{2^h - 1} \rfloor - h <s\\ \end{aligned} s′=(2h−1)(⌊2h−1s⌋−1)+i=1∑h−1(2i−1)=(2h−1)⌊2h−1s⌋−h<s 因此 x ≥ ⌊ s 2 h − 1 ⌋ \begin{aligned} x \ge \lfloor \frac{s}{2^h - 1} \rfloor \end{aligned} x≥⌊2h−1s⌋。- 综上, x = ⌊ s 2 h − 1 ⌋ \begin{aligned} x = \lfloor \frac{s}{2^h - 1} \rfloor \end{aligned} x=⌊2h−1s⌋。
- 现在问题转化为用 2 i − 1 ( 1 ≤ i < h ) 2^i - 1(1 \le i < h) 2i−1(1≤i<h) 的和来表示 s − ( 2 h − 1 ) x s - (2^h - 1)x s−(2h−1)x,又因为 2 i − 1 > ∑ j = 1 i − 1 ( 2 j − 1 ) 2^i - 1 > \sum \limits_{j = 1}^{i - 1}(2^j - 1) 2i−1>j=1∑i−1(2j−1),直接从大到小枚举 i i i,贪心填入即可。
- 考虑 x x x 同时有左孩子和右孩子的情况,设从左孩子往下走所形成的链(包含点 x x x)的长度为 h 1 ( h 1 ≥ 2 ) h_1(h_1 \ge 2) h1(h1≥2),从右孩子往下走所形成的链(包含点 x x x)的长度为 h 2 ( h 2 ≥ 2 ) h_2(h_2 \ge 2) h2(h2≥2)。
- 同样地,若往下走的过程中都是往左孩子走,路径的编号和 = 2 x ( 2 h 1 − 1 − 1 ) + ( 2 x + 1 ) ( 2 h 2 − 1 − 1 ) + x = ( 2 h 1 + 2 h 2 − 3 ) x + 2 h 2 − 1 − 1 \begin{aligned} & = 2x(2^{h_1 - 1}-1) + (2x+1)(2^{h_2 - 1} - 1) + x\\ & = (2^{h_1} + 2^{h_2} - 3)x + 2^{h_2 - 1} - 1\\ \end{aligned} =2x(2h1−1−1)+(2x+1)(2h2−1−1)+x=(2h1+2h2−3)x+2h2−1−1
- 同理可证:
当 s , h 1 , h 2 s, h_1, h_2 s,h1,h2 固定时,若存在合法的 x x x, x x x 为定值 ⌊ s − 2 h 2 − 1 + 1 2 h 1 + 2 h 2 − 3 ⌋ \begin{aligned} \lfloor \frac{s - 2^{h_2 - 1} + 1}{2^{h_1} + 2^{h_2} - 3}\rfloor \end{aligned} ⌊2h1+2h2−3s−2h2−1+1⌋。
- 现在问题转化为在 2 i 1 − 1 ( 1 ≤ i 1 ≤ h 1 − 2 ) 2^{i_1} - 1(1 \le i_1 \le h_1 - 2) 2i1−1(1≤i1≤h1−2) 以及 2 i 2 − 1 ( 1 ≤ i 2 ≤ h 2 − 2 ) 2^{i_2} - 1(1 \le i_2 \le h_2 - 2) 2i2−1(1≤i2≤h2−2) 中选取若干个数字来表示 s − ( 2 h 1 + 2 h 2 − 3 ) s − 2 h 2 + 1 s - (2^{h_1} + 2^{h_2} - 3) s - 2^{h_2} + 1 s−(2h1+2h2−3)s−2h2+1,显然不能再像上面那样贪心了。
- 枚举选出的数字个数 c n t cnt cnt,把问题进一步转化为在 2 i 1 ( 1 ≤ i 1 ≤ h 1 − 2 ) 2^{i_1} (1 \le i_1 \le h_1 - 2) 2i1(1≤i1≤h1−2) 和 2 i 2 ( 1 ≤ i 2 ≤ h 2 − 2 ) 2^{i_2} (1 \le i_2 \le h_2 - 2) 2i2(1≤i2≤h2−2) 中选取若干个数字来表示 v = s − ( 2 h 1 + 2 h 2 − 3 ) s − 2 h 2 + c n t + 1 v = s - (2^{h_1} + 2^{h_2} - 3) s - 2^{h_2} + cnt + 1 v=s−(2h1+2h2−3)s−2h2+cnt+1。
- 因为
2
i
2^i
2i 可以看成是二进制位上的
+1
,考虑数位DP
。 - 设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示从第低到高处理到第 i i i 位、已经选了 j j j 个数字且对第 i + 1 i + 1 i+1 位是/否有进位 ( k = 0 / 1 ) (k = 0/1) (k=0/1) 时的方案数,容易得到转移: f [ i + 1 ] [ j + a + b ] [ ⌊ k + a + b 2 ⌋ ] + = f [ i ] [ j ] [ k ] \begin{aligned} f[i + 1][j + a + b][\lfloor \frac{k + a + b}{2} \rfloor] += f[i][j][k]\\ \end{aligned} f[i+1][j+a+b][⌊2k+a+b⌋]+=f[i][j][k]
- 其中 a , b a, b a,b 表示第 i i i 位在 2 i 1 ( 1 ≤ i 1 ≤ h 1 − 2 ) 2^{i_1}(1 \le i_1 \le h_1 - 2) 2i1(1≤i1≤h1−2) 和 2 i 2 ( 1 ≤ i 2 ≤ h 2 − 2 ) 2^{i_2}(1 \le i_2 \le h_2 - 2) 2i2(1≤i2≤h2−2) 中是否选了数,需要根据 h 1 , h 2 h_1,h_2 h1,h2 进行限制,并且保证 ( k + a + b ) m o d 2 (k + a + b) \mod 2 (k+a+b)mod2 的值和 v v v 的第 i i i 位相同。
- 总的时间复杂度 O ( T d 5 ) \mathcal O(Td^5) O(Td5)。
Code
#include <bits/stdc++.h>
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 put(T x)
{
if (x > 9)
put(x / 10);
putchar(x % 10 + 48);
}
typedef long long ll;
const int N = 55;
const int M = 105;
int T, d, c;
ll a, b, s, f[N][M][2];
template <class T>
inline void CkMin(T &x, T y) {x > y ? x = y : 0;}
template <class T>
inline T Max(T x, T y) {return x > y ? x : y;}
template <class T>
inline T Min(T x, T y) {return x < y ? x : y;}
inline int askD(ll x)
{
int cnt = 0;
while (x)
x >>= 1, ++cnt;
return cnt;
}
inline ll askVal()
{
int da = askD(a), db = askD(b);
if (da > db)
std::swap(a, b), std::swap(da, db);
ll ans = 0;
while (db > da)
{
ans += b;
b >>= 1;
--db;
}
while (a != b)
{
ans += a + b;
a >>= 1;
b >>= 1;
}
return ans + a;
}
inline int solve1()
{
int ans = 0;
for (int h = 2; h <= d; ++h)
{
ll x = s / ((1ll << h) - 1);
if (!x)
break ;
if (askD(x) + h - 1 > d)
continue ;
ll delt = s - ((1ll << h) - 1) * x;
for (int j = h - 1; j >= 1; --j)
if (delt >= (1ll << j) - 1)
delt -= (1ll << j) - 1;
!delt ? ++ans : 0;
}
return ans;
}
inline ll solve2()
{
ll res = 0;
for (int h1 = 2; h1 <= d; ++h1)
for (int h2 = 2; h2 <= d; ++h2)
{
if (s - (1ll << h2 - 1) + 1 <= 0)
break ;
ll x = (s - (1ll << h2 - 1) + 1) / ((1ll << h1) + (1ll << h2) - 3);
if (!x)
break ;
if (askD(x) + Max(h1, h2) - 1 > d)
continue ;
ll delt = s - ((1ll << h1) + (1ll << h2) - 3) * x - (1ll << h2 - 1) + 1;
int tot = h1 + h2 - 4;
for (int cnt = 0; cnt <= tot; ++cnt)
if (!(delt + cnt & 1))
{
delt += cnt;
int ds = askD(delt) + 1;
for (int i = 1; i <= ds + 1; ++i)
for (int j = 0, jm = i - 1 << 1; j <= jm; ++j)
f[i][j][0] = f[i][j][1] = 0;
f[1][0][0] = 1;
for (int i = 1; i <= ds; ++i)
for (int j = 0, jm = Min(i - 1 << 1, tot); j <= jm; ++j)
for (int k = 0; k < 2; ++k)
if (f[i][j][k])
for (int a = 0, am = i < h1 - 1 ? 1 : 0; a <= am; ++a)
for (int b = 0, bm = i < h2 - 1 ? 1 : 0; b <= bm; ++b)
if ((k + a + b & 1) == (delt >> i & 1))
f[i + 1][j + a + b][k + a + b >> 1] += f[i][j][k];
res += f[ds + 1][cnt][0];
delt -= cnt;
}
}
return res;
}
int main()
{
read(T);
while (T--)
{
read(d);
read(a);
read(b);
read(c);
s = askVal();
put(c == 1 ? s : solve1() + solve2() - (s >= (1ll << d))), putchar('\n');
}
}