zoukankan      html  css  js  c++  java
  • [CF791D]Bear and Tree Jumps 树上DP

    题面:

    给定一颗大小为\(n\)的树,给定一个k,求\(\sum_{i=1}^n \sum_{j=1}^n \lceil \frac{dis(i,j)}{k} \rceil\)

    范围&性质:\(1\le n \le 2\times 10^5,1\le k\le 5\)

    分析:

    朴素暴力做法:

    对于每一个点dfs一遍,统计答案,复杂度\(O(n^2)\)

    正解:(前排膜拜 Orz)

    先考虑k=1怎么做,相当于求树上任意两点间路径和,直接枚举每条边,求出左右两部分内点的个数\(num1,num2\),相乘就好了,复杂度\(O(n)\)

    那怎么向k>1扩展呢,问题在于k>1时路径长度除以k会有余数,那我们就考虑把余数补齐,答案就变成了 \(\frac{ans+\sum f(i,j)}{k}\),其中\(f(i,j)\)表示将\(dis(i,j)\)补成k的倍数需要的代价,这样就可以消掉上取整符号的影响了

    那么问题就转化成了如何求\(\sum f(i,j)\),这时候就利用到k很小这一性质,我们记\(dp[i][j]\)表示u的子树内到根节点距离\(k\)\(j\)的点的个数,对于树上任意两点\(a,b\)而言,他们之间的距离\(dis(a,b)=dep[a]+dep[b]-2*dep[lca]\)\(f(a,b)=(dis(a,b)-k)mod \ k\),转移的时候我们就可以枚举\(u,v\)中dp状态第二维\(i,j\),这些点之间的距离\(dis=(i+j-dep[u]) mod\ k\)(因为\(u,v\)\(lca\)\(u\))单个点对需要的代价\(f=(dis-k)mod\ k\),由乘法原理得总的代价为\(f(i,j)\times dp[u][i]\times dp[v][j]\)

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	const int maxn = 200005;
    	int cnt=0,head[maxn];
        long long dp[maxn][5],siz[maxn],ans=0;
        int k,n;
    	
    	struct edge
        {
        	int to,nxt;
    	}e[maxn<<1];
    	
    	void add(int u,int v)
    	{
    		e[++cnt].to=v;
    		e[cnt].nxt=head[u];
    		head[u]=cnt;
    	}
    	
    	void dfs(int u,int fa,int dep)
    	{
    		dp[u][dep%k] = 1;siz[u]=1;
    		for (int i=head[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if (v==fa) continue;
    			dfs(v,u,dep+1);
    			for (int j = 0;j < k;j++)
    			{
    				for (int r = 0;r < k;r++)
    				{
    					int dis = (j + r - dep * 2) % k;
    					int rev = (k - dis) % k;
    					ans += rev*dp[u][j] * dp[v][r];
    				}
    			}
    			siz[u]+=siz[v];
    			for (int j = 0;j < k;j++) dp[u][j] += dp[v][j];
    			ans += (n - siz[v])*siz[v];
    		}
    	}
    
    	
    	void work()
    	{
    		scanf("%d%d",&n,&k);
    		for (int i=1,x,y;i < n;i++)
    		{
    			scanf("%d%d",&x,&y);
    			add(x,y);add(y,x);
    		}
    		dfs(1, -1, 0);
    		printf("%lld\n",ans/k);
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    【Leetcode】23. Merge k Sorted Lists
    【Leetcode】109. Convert Sorted List to Binary Search Tree
    【Leetcode】142.Linked List Cycle II
    【Leetcode】143. Reorder List
    【Leetcode】147. Insertion Sort List
    【Leetcode】86. Partition List
    jenkins 配置安全邮件
    python 发送安全邮件
    phpstorm 同步远程服务器代码
    phpUnit 断言
  • 原文地址:https://www.cnblogs.com/youth518/p/13677707.html
Copyright © 2011-2022 走看看