Jzoj4888 最近公共祖先

满k叉树LCA深度和计算
本文探讨了满k叉树中所有节点对的最近公共祖先(LCA)的深度之和问题,并给出了一种高效的数学计算方法。通过分析节点间的配对关系,推导出简洁的计算公式,最终利用快速幂和逆元技巧实现了O(lgN)的时间复杂度求解。

YJC最近在学习树的有关知识。今天,他遇到了这么一个概念:最近公共祖先。对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。YJC很聪明,他很快就学会了如何求最近公共祖先。他现在想寻找最近公共祖先有什么性质,于是他提出了这样的一个问题:n层的满k叉树T,求对于每一对(i,j)(1≤i,j≤T的点数),LCA(T,i,j)的深度的和是多少。这个数字n层的满k叉树指一棵带标号的有根树,深度为i(0≤i<n)的点有k^i个,所有深度≠n-1的点都有k个孩子。YJC发现他不会做了,于是他来问你这个问题的答案。这个答案可能很大,你只需要告诉他答案%998244353的值就可以了。

​对于30%的数据,满足2≤n,k≤8;
对于50%的数据,满足2≤n,k≤1000000;
对于100%的数据,满足2≤n,k≤998244351。

显然不是叫你写lca吧。。。

对于每个节点我们考虑他的所有子节点能构成多少对

选取一个节点x,设其所在子树大小为size

一个节点s能和不在同一个子树内的所有节点匹配,所以就有size*(k-1)/k种选择方法

所以x的贡献=deep[x]*size*size*(k-1)/2k

但是这样不够快,我们需要得到O(lg N)的做法

推导出(k-1)Answer=Σi*(k^(2n-i-1)-k^i){i∈[0,n)}

继续利用 Σi*k^i {i∈[0,n)}=n*Σk^i - ΣΣk^j {j∈[0,i)} 和等比数列求和公式

我们得到

Answer=k^2n-k-(2n-1)*k^n*(k-1)/(k-1)^3

可以用快速幂+逆元求解

完成(这就是一道数学计算题嘛

#include<stdio.h>
#define M 998244353
#define L long long
L pow(L x,int k){
	L S=1;
	for(;k;x=x*x%M,k>>=1)
		if(k&1) S=S*x%M;
	return S;
}
int main(){
	freopen("lca.in","r",stdin);
	freopen("lca.out","w",stdout);
	L n,k,S; scanf("%lld%lld",&n,&k);
	S=pow(k,n*2);
	S=(S-k-(2*n-1)*pow(k,n)%M*(k-1)%M+M+M)%M;
	L inv=pow(k-1,M-2);
	S=S*inv%M*inv%M*inv%M;
	printf("%lld\n",S);
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值