0%

2025-2026 ICPC NERC, Kyrgyzstan Regional Contest 吉尔吉斯斯坦——I. Cutting Trees(这种题目呢,显然是需要你去观察得到一个结论。但是怎么样去观察呢?往往这些题目具有自相似的这个特性,因此我们可以从一层开始,先只考虑一层,然后再考虑下面一层,分层的去解决这个问题)

题目大意

  • 第 1 棵树:仅包含节点 11

  • 第 2 棵树:加入节点 22 并与节点 11 相连,根节点为 22

  • nn 棵树的构建(由第 n1n-1 棵树生成)

    1. 从第 n1n-1 棵树的根节点出发,向下寻找一条通往叶子节点的路径。在每一步选择子节点时,总是选择编号最大的那个子节点。
    2. 删除该路径上原有的所有边。
    3. 加入编号为 nn 的新节点,将 nn 与刚才路径上的每一个节点分别用一条边相连。
    4. 节点 nn 成为第 nn 棵树的新根

问题描述

给定两个整数 nnvv1vn10181 \le v \le n \le 10^{18}),请计算在 nn 棵树中,从根节点(节点 nn)到节点 vv 的最短路径上,所有经过节点的编号之和(包含起点 nn 和终点 vv)。

输入格式

一行包含两个整数 nnvv

输出格式

输出一个整数 SS,表示路径节点编号之和。

样例数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Input
2 1
Output
3

Input
3 2
Output
5

Input
6 1
Output
12

Input
9 6
Output
23

样例解释

image

6 1 为例(输出 12):

  1. T2:根 22,边 (2,1)(2,1)

  2. T3:T2 路径为 212 \to 1。删除 (2,1)(2,1)。加入 33,连接 (3,2),(3,1)(3,2), (3,1)。根 33

  3. T4:T3 根 33,子节点 {2,1}\{2, 1\},最大子节点 22(叶子)。路径 323 \to 2。删除 (3,2)(3,2)。加入 44,连接 (4,3),(4,2)(4,3), (4,2)。保留 (3,1)(3,1)。根 44

  4. T5:T4 根 44,子节点 {3,2}\{3, 2\},最大子节点 333311)。路径 4314 \to 3 \to 1。删除 (4,3),(3,1)(4,3), (3,1)。加入 55,连接 (5,4),(5,3),(5,1)(5,4), (5,3), (5,1)。保留 (4,2)(4,2)。根 55

  5. T6:T5 根 55,子节点 {4,3,1}\{4, 3, 1\},最大子节点 444422)。路径 5425 \to 4 \to 2。删除 (5,4),(4,2)(5,4), (4,2)。加入 66,连接 (6,5),(6,4),(6,2)(6,5), (6,4), (6,2)。保留 (5,3),(5,1)(5,3), (5,1)。根 66

  6. 查询:在 T6 中从 6611。由于 66 直接连接 55,且 55 此时保留了与 11 的连接((5,1)(5,1) 在生成 T6 时未被选中删除),路径为 6516 \to 5 \to 1

  7. 结果6+5+1=126 + 5 + 1 = 12

思路讲解

AI 说的实在是,怎么说呢?讲的不是说很好啊,这 AI 讲的不是说很好,所以我认为真正的 AGI 啊,真正的 AGI 肯定是要会画图的。啊,现在的这个 AI 这个画图能力 比较一言难尽吧。

哎,不扯了,我们来看看这道题目。这道题目的规律,我这样子画了一张图啊,我觉得就很明显了。这就是所谓 AI 口中的自相似。你要说是自相似也也没什么问题,但是呢,自相似,但又没有那么相似。首先要注意到,根节点的孩子是 N 减一、 N 减二、 N 减四、 N 减八、 N 减十六。云云。这个注意到还是有一定难度啊,还是有一定难度,因为他毕竟哎,毕竟他不是一个这个线性的规律,对吧?

然后你注意到这个规律以后呢,你可以把这个规律应用于下面的节点,它们的孩子节点是怎么样子的。我们会发现,如果说这个根节点是 N 减一,那么令 N 减一等于 N 那么它的叶子节点,它的孩子节点就是 N 撇减二、 N 撇减四、 N 撇减八。如果令 N 撇减二等于 N 撇撇。那么它的孩子节点就是 N 撇撇减四。

image

好,现在的问题就来到什么呢?你注意到了这个规律,要写一个程序,在 LogN 的时间复杂度内求解。

注意啊,就是减法非常难以考虑。你去减法的话,你就会发现,哎,他怎么退位呀,进位呀,反正反正很难考虑。但是不妨反过来想。我们是要判断一一个点,就这个数在哪棵子树内。那我们就想,它能不能通过某种方法去加到它的根,对吧?去加回到它的根。加法比减法好想的多

究其原因呢,加法比减法好想,其实是因为减法它会影响其后面的位,加法只会影响它前面的位。减法的这种回退的特性是我们最讨厌的。

判断的逻辑如此书写即可。不难发现的,我们实际上就是想要查看后 CI +1 位它的这个是否一样。之所以查看的是后 CI 加一位,是因为加法它只能改变 CI 加二位以及以后的位,它的这个情况。

1
2
3
4
5
6
7
8
9
10
11
// 判断 V 属不属于 u,ci 的这个子树。
auto check=[&](ll u,ll ci) -> bool {
// 查看后 CI +1 位它的这个是否一样,所需要的 mask。
ll mask=(1ll<<(ci+1))-1;
// 直接进行与运算以后,就得到了 V 的后 CI +1 位,以及 U 的后 CI +1 位。
ll a=mask&V,b=mask&u;
if (a==b) {
return true;
}
return false;
};

有了这个 check 函数以后,我们就写一个递归式的 solve 函数,就可以非常轻松的求解这个东西了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
auto solve=[&](auto && self,ll u,ll ci) -> void {
ans+=u;
if (u==V) {
return;
}
for (ll j=ci+1;;j++) {
ll to=u-(1ll<<j);
if (to<=0) {
break;
}
// 下面我们就是要判断我们想求的 V 到底在哪个子树之中呢?
// 严格来讲,其实是判断 V 属不属于 to 的这个子树。
if (check(to,j)) {
self(self,to,j);
break;
}
}
};

AC代码

哎呀,这个 CF 挂的。今天是2月20号,这 CF 还是在,就是已经挂了5个多小时了。那么AI 我让 AI 对拍了一下这个程序是对的。啊,他拍了2000多组数据,都没发现这个 hack 那么这个应该就是对的。这个我这个也是一遍写出来的,挺爽的。

AC

https://codeforces.com/gym/106169/submission/363673850