Fish eating fruit
\[ Time Limit: 1000 ms \quad Memory Limit: 262144 kB \]
题意
大体的题意就是给出一棵树,求每一对点之间的距离,然后把该距离存在距离 \(\mod 3\) 的位置,输出总和。
思路
令两个 \(dp\) 数组和两个辅助 \(dp\) 的数组。
\(dp1[i][j]\) 表示从 \(i\) 为起点往下到各个点距离 \(\mod 3\) 后为 \(j\) 的距离总和。
\(cnt1[i][j]\) 表示以 \(i\) 为起点往下到各个点距离 \(\mod 3\) 后为 \(j\) 的节点个数。
\(dp2[i][j]\) 表示从 \(i\) 起点往上一步后到各个点距离 \(\mod 3\) 后为 \(j\) 的距离总和。
\(cnt2[i][j]\) 表示以 \(i\) 为起点往上一步后到各个点距离 \(\mod 3\) 后为 \(j\) 的节点个数。
对于两个 \(dp\) 分别跑一遍 \(dfs\)
对于 \(dp1\) 比较好处理,直接往下 \(dfs\)
以 \(u\) 开始的答案等于从 \(v\) 开始的答案加上这一条边 \(w\) 的贡献,可以得到
\[ dp1[u][(j+w)\%3] = \sum (dp1[v][j] + cnt1[v][j]*w)\\ cnt1[u][(j+w)\%3] = \sum cnt1[v][j] \]
对于 \(dp2\) 会比较麻烦,需要用 \(fa\) 节点向上的贡献在加上 \(fa\) 节点往下的贡献在减去 \(fa\) 节点往 \(u\) 走的贡献。这些节点就是 \(u\) 往上走一步后可以走到的所有节点。这样算出真实的节点数和距离总和,然后 \(u\) 才能开始转移。
设 \(faw\) 为从 \(u\) 到 \(fa\) 的路径长度
计算真实的节点数:
\[ c[j] = cnt2[fa][j]+cnt1[fa][j]\\ c[(j+faw)\%3] -= cnt1[u][j] \]
计算真实的距离总和:
\[ d[j] = dp2[fa][j]+dp1[fa][j] \\ d[(j+faw)\%3] -= dp1[u][0]+cnt1[u][j]*faw \]
则最后的 \(dp2\) 就可以利用 \(d\) 和 \(c\) 得到了
\[ dp2[u][(j+faw)\%3] = c[j]*faw+d[j] \\ cnt2[u][(j+faw)\%3] = c[j] \]
/***************************************************************
> File Name : a.cpp
> Author : Jiaaaaaaaqi
> Created Time : Mon 16 Sep 2019 08:55:33 PM CST
***************************************************************/
#include