倍增算法(含L3-1 银白之森题解)
本文背景
天梯赛后被建议来吃吃“银白之森”这坨,吃完了认为确实是一坨,故写本文来介绍一下这个题所涉及到的倍增算法。
朴素倍增
对于这样一个问题:
从0出发,到7格外的位置上,如何快速转移你的位置。
最简单最暴力的算法就是一格一格走(但是给到 $ 1≤k≤10^{12} $ 你不就炸了吗?)。
于是看这个数的二进制,发现:
任何一个数都可以用$ n $个$ 2^k $的和来表示。
则对于这样一个图:
我们发现从0到7需要跨越 $ 7_{10} (111_2) $格,即 $ 7 = 2^0 + 2^1 + 2^2 $,于是我们建立一个状态表示数组$ f $,使得 $ f[i][j] $ 表示从1出发,跨越$ 2^{j} $ 步所到达的地方。
以这个图为例:我们依次经过$ f[0][0]=1,f[1][1]=3,f[3][2]=7 $到达了第7格。
这时有人发现:
$$ 2^{n} = 2^{n-1}\times2 = 2^{n-1}+2^{n-1} $$这样从$i$出发,走$2^{j}$格,就可以看成从$i$出发,走$2^{j-1}$格后到达$i+A$,再走$2^{j-1}$格到达目的地,递推关系如下:
$$ f[i][j] = f[f[i][j-1]][j-1] $$所以,如果我们预先处理好一个这样的状态表示数组$ f $,那查询的时候时间复杂度会大大降低,该算法的时间复杂度为$ O(n \log k) $。
Eg:L3-1 银白之森 作者:Chocola
题目描述 :
在不知名的银白之森,共有 $n$ 个节点。
每个节点处,生活着一名魔法师。在每个节点,有一条通向其他节点的单向道路。
不知道该说运气好还是不好,你被一阵神秘的力量所影响,落在了某个节点上。接下来你可以沿着这些单向道路移动 $k$ 次。每利用单向道路移动到一个节点,这个节点处的魔法师会为你进行一次赐福,获得等于节点编号数量的命定之缘。(例如,当节点编号为 3 时,经过这个节点可以获得 3 个命定之缘)。
需要注意的是,反复经过同一个节点时,可以重复获得命定之缘。
非常幸运,你提前掌握了整个银白之森的道路图。但同时非常不幸,你会被神秘的力量丢到某个随机的节点上 $q$ 次。那么,聪明如你,能求出来这 $q$ 次移动分别能获得多少命定之缘吗?
输入格式 :
一行两个正整数 $ n $ 和 $ q $ ,表示银白之森总共有 $ n $ 个节点,编号为 1 到 $ n $ 。总共会有 $ q $ 次神秘力量。 $(1≤n,q≤100,000 )$
接下来一行 $ n $ 个整数,第 $ i $ 个整数表示节点 $ i $ 处的单向道路通向哪个节点。(保证范围在 $ [1,n] $ 内,单向道路可以指向自己)
接下来 $ q $ 行,每行两个整数 $ x,k $ ,表示你该次神秘力量影响下落在了点$ x $ 处,你可以沿着单向道路移动 $ k $ 次获得赐福。$(1≤x≤n ,1≤k≤10^{12})$
输出格式 :
共 $ q $ 行,每行表示一次神秘力量影响下,你通过赐福获得的命定之缘的数量。
输入样例:
|
|
输出样例:
|
|
样例解释
第一次移动路径:1 -> 2 -> 3 -> 1 -> 2 -> 3
获得的命定之缘共计2 + 3 + 1 + 2 + 3 = 11
第二次移动路径:4 -> 5 -> 6 -> 6 -> 6 -> 6
获得的命定之缘共计5 + 6 + 6 + 6 + 6 = 29
分析
由于每个点只有一个固定的出边,所以每个点走 步后获得的命定之缘数量以及走到了哪一个点是可以确定的。
我们采用倍增的方式去维护每个点走 $ 2^{0},2^{1},2^{2},2^{3},2^{4}…2^{50} $ 后到达的位置以及获得的命定之缘的数量,每次询问时,将$ k $拆解成二进制数,快速跳转并计算贡献即可。
代码实现:
|
|