鉴于具有n
个节点的树(n
可以与2 * 10^5
一样大),每个节点都有与之关联的成本,让我们定义以下函数:
g(u, v) = the sum of all costs on the simple path from u to v
f(n) = the (n + 1)th Fibonacci number (n + 1 is not a typo)
我正在处理的问题要求我计算树模f(g(u, v))
中所有可能的节点对的10^9 + 7
之和。
举个例子,我们来看一个带有3
个节点的树。
1
是根,其子节点为2
和3
costs[1] = 2, cost[2] = 1, cost[3] = 1
g(1, 1) = 2; f(2) = 2
g(2, 2) = 1; f(1) = 1
g(3, 3) = 1; f(1) = 1
g(1, 2) = 3; f(3) = 3
g(2, 1) = 3; f(3) = 3
g(1, 3) = 3; f(3) = 3
g(3, 1) = 3; f(3) = 3
g(2, 3) = 4; f(4) = 5
g(3, 2) = 4; f(4) = 5
对所有值求和,并以10^9 + 7
模结果得出26
作为正确答案。
我的尝试:
我实现了一种算法,通过使用稀疏表找到最低共同祖先来计算g(u, v)
中的O(log n)
。
为了找到合适的Fibonacci值,我尝试了两种方法,即在矩阵形式上使用取幂,另一种方法是注意序列modulo 10^9 + 7
是循环的。
现在是非常棘手的部分。无论我如何进行上述计算,在计算所有可能O(n^2)
的总和时,我仍然最终会达到f(g(u, v))
对。我的意思是,只有n * (n - 1) / 2
对才有明显的改善,但这仍然是二次的。
我错过了什么?我已经在这里工作了几个小时,但是我没有办法在不实际生成二次算法的情况下得到这笔钱。
答案 0 :(得分:2)
要知道节点X的成本要包含在总和中的次数,我们将其他节点划分为3个(或更多)组:
当两个节点属于不同的组时,它们的简单路径通过X.因此,通过X的简单路径的数量为:
#Y + #A×(N - #A)+ #B×(N - #B)
因此,通过计算节点的总数N和X下的子树的大小,您可以计算节点X的成本应包括在总和中的次数。为每个节点执行此操作,您将获得总成本。
这个代码可能很简单。我假设节点N的总数是已知的,并且您可以向节点添加属性(这两个假设都简化了算法,但可以在没有它们的情况下完成)。
我们将添加 child_count 来存储节点的后代数量,并添加 path_count 来存储节点所属的简单路径的数量;两者都初始化为零。
对于每个节点,从根目录开始:
答案 1 :(得分:-1)
以下算法的运行时间为O(n ^ 3)。
树是一个没有循环的强连通图。因此,当我们想要获得所有可能的配对时,成本,我们试图找到所有对的最短路径。因此,我们可以使用Dijkstra的想法和动态编程方法解决这个问题(我从Weiss的书中得到了它)。然后我们将斐波那契函数应用于成本,假设我们已经有一个表来查找。
完成后,我们检查D [] []矩阵并将Fibonacci函数应用于每个单元格并将它们相加,并应用模运算。