版权声明:转载请说明,欢迎交流! https://blog.csdn.net/qq_39599067/article/details/82084964
(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
Catalog
Problem:Portal传送门
原题目描述在最下面。
求
.
Solution:
树形DP:
当k等于1时,答案就是每条边算贡献,
化简:
问题转为求:
第一部分就是k=1时的情况,第二部分求法是枚举每条边算贡献。
对于边
,算
左边各点 到
右边各点的距离
的和。
处理
表示从根节点到
的子树节点距离
等于
的点的个数。
本题结束。
AC_Code:
#include<bits/stdc++.h>
#define lowbit(x) (x&(-(x)))
#define mme(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
const int MXN = 2e5 + 7;
const int MXE = 1e6 + 7;
const int mod = 998244353;
const int INF = 0x3f3f3f3f;
int n, k;
vector<int> g[MXN];
LL sum[MXN], cnt[MXN][5] , ans;
void exe(int u,int Fa,int dd){
sum[u] = cnt[u][dd%k] =1;
for(int i=0;i<g[u].size();++i){
int v=g[u][i];
if(Fa==v)continue;
exe(v,u,dd+1);
sum[u]+=sum[v];
ans += sum[v]*(n-sum[v]);
for(int i = 0; i < k; ++i){
for(int j = 0; j < k; ++j){
LL tmp = ((i+j-2*dd)%k+k)%k;
tmp = ((k-tmp)%k+k)%k;
ans += tmp*cnt[u][i]*cnt[v][j];
}
}
for(int i = 0; i < k; ++i)cnt[u][i]+=cnt[v][i];
}
}
int main(){
while(~scanf("%d%d", &n, &k)){
memset(sum,0,sizeof(sum));
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;++i)g[i].clear();
for(int i=1,x,y;i<=n-1;++i){
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
ans = 0;
exe(1,-1,0);
printf("%lld\n", ans/k);
}
return 0;
}