Codeforces 791D Bear And Tree Jumps 树形DP

来源:互联网 发布:aceplayer mac 编辑:程序博客网 时间:2024/05/29 06:50

点击打开链接

题意:n个结点的树,每个结点可以跳到距离其不超k的结点上,定义f(s,t)为从s跳到t的最少次数.

n<=2e5,k<=5,求 s<t  


长度为L的路径对答案的贡献为(上取整)   f(L,k)为L还差多少能整除k f(10,3)=2
L的累加和为:sum树中任意两点距离的累加和 sz[v]为子树v的结点数,对于每条边(u,v) 总共被遍历 sz(v)*(n-sz(v)次
剩下的,只要求出segma(f(L,k)) 当路径中u为最高点时,任意两点的路径长度 = dep[x]+dep[y]-2*dep[u]

设dp[u][x] u为根时 深度%k==x的结点数 dp[u][x]+=dp[v][x]

O(k^2) 根据(前i-1组,子树v)深度枚举路径长度余k的值 dp算出方法数即可 时间复杂度为O(n*k*k)

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=2e6+20;const int inf=2e8;vector<int> e[N];ll ans;ll n,k;ll dep[N],sz[N],dp[N][6];void dfs(int u,int fa){sz[u]=1;dep[u]=(dep[fa]+1)%k;dp[u][dep[u]]=1;for(int i=0;i<e[u].size();i++){int v=e[u][i];if(v==fa)continue;dfs(v,u);sz[u]+=sz[v];ans+=(n-sz[v])*sz[v];//(u,v)'s contributionfor(int x=0;x<k;x++)//Ç°i-1×é Éî¶ÈΪxµÄ¸öÊý {for(int y=0;y<k;y++)//vÖÐÉî¶ÈΪyµÄ¸öÊý {int dis=((x+y)%k-2*dep[u]+k)%k;ans+=((k-dis)%k)*dp[u][x]*dp[v][y];//ÓàÊýΪdisµÄ·½·¨Êý }}for(int x=0;x<k;x++)dp[u][x]+=dp[v][x];}}int main(){while(cin>>n>>k){ans=dep[0]=0;int u,v;memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++)e[i].clear(),sz[i]=0;for(int i=1;i<=n-1;i++){scanf("%d%d",&u,&v);e[u].push_back(v);e[v].push_back(u);}dfs(1,0);cout<<ans/k<<endl;}return 0;} 


原创粉丝点击