P6219 题解
总体思路
将图分为若干层,$1$ 号节点在第一层,$N$ 号节点在最后一层,除 $1$ 号节点外只有相邻的两层之间有边。
手玩一下前两个Subtask,我们可以推断,当我们在新的一层加入 $M$ 个节点时,我们会把所有 $tns(1,x)$ 的总和乘上 $-(M-1)$。 同时,很显然的可以知道, $tns(1,N)=-\sum_{i=1}^{n-1}tns(1,i)$。如果我们把 $K$ 进行二进制拆分,那么我们只要每次在新的一层加入 $3$ 个节点,我们就能使 $tns(1,x)$ 的总和乘上 $-2$,所有我们一定能用至多 $3+(i-1)\times9$ 个点算出 $K$。如果我们的符号反了,我们只需要在新的一层加入两个节点就可以使总的结果乘上 $-1$。
现在的问题只剩下如何在某一个二进制位加上 $1$ 了。如果这个问题解决了,我们就可以用若干次乘二和加一的操作表示出 $K$ 的二进制拆分,也就是得到答案。如果当前的总和是负的,我们只用在当前层新建一个节点并从 $1$ 号节点向他连边。类似的,如果当前的总和是正的,先将其变为负的,再执行上面的操作。也就是说,我们新开一层,新建 $2$ 个节点,并从上一层的每个节点向他们连边,从而使答案变成负的同时加上 $1$。
该算法能用少于 $16\times log_2(K)$ 的边得到答案。
以上内容由本人翻译自官方题解,并加入了一些自己的理解。
实现细节
- 从高到低枚举二进制位的时候,要从最高的第二位开始枚举。
- 正数的 $+1$ 操作是放在新的一层,该层有 $3$ 个节点(变号有两个,加一有一个),该层需要向下一层建边。
- 用于判断符号的计数器要初始化为 $-1$。
丑陋的代码
1 | vector<int> nd[205];//存每一层的结点 |