【BestCoder Round 65D】【树形DP 容斥思想】ZYB's Tree 求距离每个节点距离不超过k的节点数

本文主要是介绍【BestCoder Round 65D】【树形DP 容斥思想】ZYB's Tree 求距离每个节点距离不超过k的节点数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ZYB's Tree

Accepts: 77
Submissions: 513
Time Limit: 3000/1500 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
问题描述
ZYBZYB有一颗NN个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数.两个点(x,y)(x,y)在树上的距离定义为两个点树上最短路径经过的边数,为了节约读入和输出的时间,我们采用如下方式进行读入输出:读入:读入两个数A,BA,B,令fa_ifai为节点ii的父亲,fa_1=0fa1=0;fa_i=(A*i+B)\%(i-1)+1fai=(Ai+B)%(i1)+1 i \in [2,N]i[2,N] .输出:输出时只需输出NN个点的答案的xorxor和即可。
输入描述
第一行一个整数TT表示数据组数。接下来每组数据:一行四个正整数N,K,A,BN,K,A,B.最终数据中只有两组N \geq 100000N1000001 \leq T \leq 51T5,1 \leq N \leq 5000001N500000,1 \leq K \leq 101K10,1 \leq A,B \leq 10000001A,B1000000
输出描述
TT行每行一个整数表示答案.
输入样例
1
3 1 1 1
输出样例
3



#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=5e5+10,M=1e6+10,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int n,K,A,B;
int first[N],id;
int w[M],nxt[M];
bool e[N];
int f[N][12],ans;
inline void ins(int x,int y)
{++id;w[id]=y;nxt[id]=first[x];first[x]=id;
}
void dfs(int x)
{e[x]=1;f[x][0]=1;for(int i=1;i<=K;++i)f[x][i]=0;for(int z=first[x];z;z=nxt[z]){	int y=w[z];if(e[y])continue;dfs(y);for(int i=1;i<=K;++i)f[x][i]+=f[y][i-1];}
}
void dp(int x)
{e[x]=0;for(int z=first[x];z;z=nxt[z]){int y=w[z];if(!e[y])continue;for(int i=K;i>=2;--i)f[y][i]+=f[x][i-1]-f[y][i-2];++f[y][1];dp(y);}int tmp=0;for(int i=0;i<=K;++i)tmp+=f[x][i];ans^=tmp;
}
int main()
{scanf("%d",&casenum);for(casei=1;casei<=casenum;++casei){scanf("%d%d%d%d",&n,&K,&A,&B);memset(first,0,n+2<<2);id=0;for(int i=2;i<=n;++i){int j=((LL)A*i+B)%(i-1)+1;ins(i,j);ins(j,i);}ans=0;dfs(1);dp(1);printf("%d\n",ans);}return 0;
}
/*
【trick&&吐槽】
1,csy向我透露说,这次BC有题可以暴力过!
于是我就写了个暴力,然后TLE……
果然还是要自己思考,不能再被骗了23332,A和B都是1e6范围的数,所以乘法可能会爆int,一定要注意啊>_<3,这么水的题比赛时候竟然没认真想过,我好蠢!【题意】
给你一棵树,树上有n(5e5)个节点,让你求出,对于所有点而言的,距离不超过K(1<=K<=10)的节点数。
然后输出这所有节点数的异或和。【类型】
树形DP【分析】
首先,这是树结构。
然后,我们尝试简化问题。
如果求的,不是对于一个节点,所有距离在[1,K]的节点数,而是限制在子树内的距离在[1,K]的节点数。
那么,这道题,我们直接一个dfs就可以搞定。
就是从叶子节点开始,距离这个节点距离为[1,K]的节点数。
然后f[x][i]=∑f[son][i-1],i∈[1,K]f[x][0]=1然而,我们还要求与非子树内的节点,怎么办呢?
我们做完之前的预处理之后,只需要从父节点寻求转移即可。我们假设,我们已经知道了距离父节点x距离为0~K的所有点的点数。我们现在要向子节点y转移。
显然,f[y][i]+=f[x][i-1]-f[y][i-2],2<=i<=K。++f[y][1];
意思是,距离父节点x为i-1的节点,转移到节点y的时候,距离就变成了i。
然而, 并非所有的节点都能做转移。y子树内的,距离为y为i-2的节点,距离父节点的距离也是i-1,但是距离y的距离并非为i。
所以我们把这些节点剔除。一个转移从子节点转移而来,另外一个转移从父节点转移而来。
同时DP的时候要注意使用合理的拓扑序,就可以顺利AC这道题啦。啦啦啦啦~【时间复杂度&&优化】
O(nk)【数据】
调试代码——
for(int i=1;i<n;++i)
{int x,y;scanf("%d%d",&x,&y);ins(x,y);ins(y,x);
}
input
14 5 1 1
1 2
2 3
3 4
4 5
1 6
6 7
7 8
8 9
9 10
1 11
11 12
12 13
13 14
output
8
*/


这篇关于【BestCoder Round 65D】【树形DP 容斥思想】ZYB's Tree 求距离每个节点距离不超过k的节点数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/610452

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs