CF771F : Bear and Isomorphic Points
CF771F : Bear and Isomorphic Points
题目传送门
题意:
在一棵树上,每一步最多走 k 步,问走完所有点对最少需要多少步
思路 && 分析:
设想一个这样的情况,树上任意两点之间的距离都是 k 的倍数,在这种情况下答案就是将所有的点对距离之和加起来(这个只需要一个简单的的 dfs 就能求出)在除以 k,但是这种情况显然只有在 k 为 1 时才会出现。
所以如果我们可以求出两个点之间的距离需要补多少就能被 k 整除(意思就是假如有两个点之间距离为 7, k 为 3,这种情况就要补 2。)在加上所有点的距离之和后除以 k 就会得到我们要的答案
具体见代码如下
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 200010;
vector<int> e[N];
// dp[i][j] 表示 i 的子树(下面写为 i 树)内有多少到根节点距离取余 m 为 j 的点
ll ans, dp[N][6];
// h 用来存每一个节点包括子树和自己有多少个点
int n, h[N], m;
void dfs(int u, int fa, int d){
h[u] = 1;
dp[u][d % m] = 1;
for(auto s : e[u]){
if(s == fa) continue;
dfs(s, u, d + 1);
//枚举组合 u 树内的节点与 s 内的节点
for(int i = 0;i < m;i ++)
for(int j = 0;j < m;j ++){
//(i - d) + (j - d) --- (因为dp里的距离是到根节点的)
// 这里 x 是两点之间的距离, y 即是要补的
int x = (i + j - 2 * d) % m;
int y = (m - x) % m;
ans += 1LL * y * dp[u][i] * dp[s][j];
}
h[u] += h[s];
for(int i = 0;i < m;i ++) dp[u][i] += dp[s][i];
// 这里是原来的距离之和
ans += 1LL * h[s] * (n - h[s]);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for(int i = 1;i < n;i ++){
int x, y;
cin >> x >> y;
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1, 0, 0);
cout << ans / m;
return 0;
}

浙公网安备 33010602011771号