(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
Catalog
Problem:Portal传送门
原题目描述在最下面。
求
∑ni=2∑i−1j=1(⌈dis[i][j]/k⌉)
∑
i
=
2
n
∑
j
=
1
i
−
1
(
⌈
d
i
s
[
i
]
[
j
]
/
k
⌉
)
.
Solution:
树形DP:
当k等于1时,答案就是每条边算贡献,
ans+=sum[u]×(n−sum[u])
a
n
s
+
=
s
u
m
[
u
]
×
(
n
−
s
u
m
[
u
]
)
化简:
⌈L/k⌉=(L+f(L,k))/kf(L,k)=k−L%k
⌈
L
/
k
⌉
=
(
L
+
f
(
L
,
k
)
)
/
k
f
(
L
,
k
)
=
k
−
L
%
k
问题转为求:
(∑L+∑f(L,k))/k
(
∑
L
+
∑
f
(
L
,
k
)
)
/
k
第一部分就是k=1时的情况,第二部分求法是枚举每条边算贡献。
对于边
u−>v
u
−
>
v
,算
u
u
左边各点 到 右边各点的距离
modk
m
o
d
k
的和。
处理
cnt[u][i]
c
n
t
[
u
]
[
i
]
表示从根节点到
u
u
的子树节点距离等于
i
i
的点的个数。
本题结束。
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;
}