P7108 【移花接木】题解
AsunderSquall · · 题解
刚推出式子时不知道为什么被卡常了,非常自闭 link
声明1:下文由于本人菜,分不清“结点”和“节点”,请忽略。
update:修改了一个笔误。
题意
有一个高度无限的有根满
(题意中有描述的不到位的地方,仅供回忆题目,具体见原题目
题解
声明2:下文所说的“删除结点”为删除结点及其子树。
也就是说删得只剩根节点,输出
如图为
if (h==0) cout<<(a);
只需要将多余的子树删去即可
设根为第
如图为
if (a==b) cout<<(ksm(a,h+1,mod));
原始的树为一条链
那么我们可以把满
设
我们考虑使一棵满
那么有
对于根的每个儿子,都可以分成
考虑根,只要连到一条经过儿子的链上就行了
if (a==1) cout<<(ksm(b,h,mod));
要把树删得只剩一条链
那么第
如图为
if (b==1) cout<<(((a-1)*h+a)%mod);
我感觉后面的点都没什么用……其实只要把这个式子搞出来后面就一样了。。。
分为
我们要把满
那么我们分为两个步骤
- 把前面
h 层补成满b 叉树 - 删去第
h+1 层多余的结点
对于第一步,我们考虑一层一层拖子树。
先把第
这个时候第
第
那么我们只需要将他们加起来
对于第二步,第
所以答案为
真 的 吗 ?
显然,如果我们将本来第二步中应该删去的子树给拖走,那么就省去了删除这个结点这一步骤。
所以答案为
这样说可能有点模糊,我们来举个例子。
Example:
下面的图的标号和上面 出现什么标什么 的标号不太一样,对于标号为
比如说第一层,如果我们随便拖一个下面的节点过来,这样是可行的,但是不够优秀。
我们知道,到时候我们肯定要把
同理,要使
然后
最后把底部的所有节点全部删去
同样分为两个步骤
- 把前面
h 层删成满b 叉树 - 删去第
h+1 层多余的结点
对于第一步,我们考虑一层一层删子树,答案与
对于第二步,为
如图为
事实上我并不理解为什么到了这一步还推不出正确答案(似乎也没有被卡到这一档部分分的人)。
显然
这个应该小学就会了吧。。。
同时这个也可以解释为什么
注意
代码
真的很短,为什么不去自己写呢?
#include<bits/stdc++.h>
#define int long long
#define rd(x) x=read()
using namespace std;
const int mod=1e9+7;
inline int read(){int x=0,f=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int ksm(int x,int y,int z){int ret=1;while (y){if (y&1) ret=(ret*x)%z;x=(x*x)%z;y>>=1;}return ret;}
int INV(int x){return ksm(x,mod-2,mod);}
int a,b,h;
int T;
signed main()
{
rd(T);
while (T--)
{
rd(a);rd(b);rd(h);
if (b==1) cout<<(((a-1)*h+a)%mod);else
if (a<=b) cout<<ksm(b,h,mod)*a%mod;
else cout<<(a*ksm(b,h,mod)%mod+(ksm(b,h,mod)-1)*(a-b)%mod*INV(b-1)%mod)%mod;
putchar('\n');
}
}