Codeforces771C: Bear and Tree Jumps-树形DP-算贡献经典题变形

版权声明:转载请说明,欢迎交流! https://blog.csdn.net/qq_39599067/article/details/82084964

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

Catalog

Problem:Portal传送门

 原题目描述在最下面。
 求 i = 2 n j = 1 i 1 ( d i s [ i ] [ j ] / k ) .

Solution:

这里写图片描述
树形DP:
 当k等于1时,答案就是每条边算贡献, a n s + = s u m [ u ] × ( n s u m [ u ] )
 化简: L / k = ( L + f ( L , k ) ) / k f ( L , k ) = k L % k
 问题转为求: ( L + f ( L , k ) ) / k
 第一部分就是k=1时的情况,第二部分求法是枚举每条边算贡献。
 对于边 u > v ,算 u 左边各点 到 v 右边各点的距离 m o d k 的和。
 处理 c n t [ u ] [ i ] 表示从根节点到 u 的子树节点距离 m o d k 等于 i 的点的个数。
a n s + = n e e d u , v c n t [ u ] [ i ] c n t [ v ] [ j ] i [ 0 , k 1 ] , j [ 0 , 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;
}


Problem Description:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/82084964