参天大树[题解]
参天大树
题目大意
给出一个 层的满二叉树,其根节点编号为 ,对于每一个 ,编号为 的节点有编号为 与编号为 的子节点。
需要从该二叉树的节点中选出一些节点(可以相同),求出所有情况中他们 的和。
则我们需要求出下面这个式子的值:
最终答案对 取模。
分析
拿到这个题,我们可以换一个角度来思考,不妨想一想如果我们想要选出节点的 为 节点,有多少种不同的情况。
其实我们可以分为以下三种情况:
-
这两个点就是 与 ,这样就能保证有 的贡献,很显然该情况只会出现一次。
-
这两个点分别在 的左子树与右子树,如上图,这样也能保证他们的 恰为 ,则这种情况的总数肯定就是左子树的大小乘右子树的大小还要乘 ,注意这里的乘 是因为除了选择同一个点的情况其余情况都可以反转。
-
固定其中一个点为 ,剩余的点在 的子树中选取,则很显然情况数位 乘 所有后代的数量。
那么,我们就能处理出 为 时的所有贡献了。
设 为 一个子树的大小,设根节点的层数为 , 的层数为 ,则易有 。
则当前的可知道 为 的贡献为:
进行化简即为
接下来考虑如何将其转化到层上去,我们发现,其实每层的节点他们的子树都是一模一样的,所不同的只是系数,我们设 表示第 层所有节点编号值的和,则有:
设 表示第 层最左边节点的编号, 表示第 层最右边节点的编号,则有:
则
展开即为
然后再展开
然后,又有
后面的两个求和式用到等比数列求和的知识,即
最后得到的答案为:
然后就做完了。
更新:此题根本不用快速幂,可以通过直接 的预处理避免超时,下面是最新代码。
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10,MOD=998244353;
inline ll read()
{
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
ll dis[N];
int main()
{
ll t=read();
dis[0]=1;
for(register int i=1;i<=1e6;i++) dis[i]=dis[i-1]*2%MOD;
while(t--){
ll n=read(),temp=dis[n-1];
ll ans=((3*n%MOD-4+MOD)%MOD*temp%MOD*temp%MOD+temp*2%MOD+MOD)%MOD;
printf("%lld\n",ans);
}
return 0;
}
本文作者:╰⋛⋋⊱๑落叶๑⊰⋌⋚╯
本文链接:https://www.cnblogs.com/Defoliation-ldlh/p/14496177.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步