题解 P7108 【移花接木】
数学题,高度 \(\infty\) 是为了防止你想多考虑嫁接是否够用。
分析:
- \(\text{case1}\):当 \(a\ge b\) 时,只需要砍树就行,嫁接没有任何用处。
第 \(0\) 层要砍掉 \((a-b)\to(a-b)\times b^0\) 个树枝;
第 \(1\) 层要砍掉 \((a-b)\times b^1\) 个树枝;
第 \(2\) 层要砍掉 \((a-b)\times b^2\) 个树枝;
\(\cdots\)
第 \(h-1\) 层要砍掉 \((a-b)\times b^{h-1}\) 个树枝;
第 \(h\) 层要全部砍光,也就是 \(a\times b^h\) 个树枝。
所以一共砍掉了:
\[(a-b)\times\left(b^0+b^1+b^2+\cdots+b^{h-1}\right)+a\times b^h
\]
\[=(a-b)\times \frac{1-b^h}{1-b}+a\times b^h
\]
用快速幂 \(+\) 逆元直接求就行。
注意 \(b=1\) 时的特判。
- \(\text{case2}\):当 \(a<b\) 时,先用嫁接把 \(h\) 层以下的枝补全了,再考虑把 \(h\) 层砍光。
换的时候可以贪心,用第 \(h\) 层的树枝嫁接给之前的。
第 \(0\) 层要接 \((b-a)\to (b-a)\times b^0\) 个树枝;
第 \(1\) 层由于上一层新添了 \(b-a\) 个树枝,所以要接 \((b-a)\times b^1\) 个树枝;
\(\cdots\)
第 \(h-1\) 层就要接 \((b-a)\times b^{h-1}\) 个树枝。
所以一共只需要 \(a\times b^h\) 次操作。
快速幂直接算。
时间复杂度是 \(\mathcal O(T\times log(h))\)。
代码:
#include "cstdio"
#include "cctype"
#include "algorithm"
#define mod 1000000007
#define ll long long
ll ans, t, a, b, h;
char buffer[1 << 28], *S = buffer, puffer[1 << 28], *T = puffer;
inline ll read() {
int x(0), f(0);
while (!isdigit(*S))
f |= (*S++ == '-');
while (isdigit(*S))
x = (x << 1) + (x << 3) + (*S++ ^ 48);
return f ? -x : x;
}
inline void write(ll x) {
int num[28], sp = 0;
if (x < 0)
*T++ = '-', x = -x;
if (!x)
*T++ = 48;
while (x)
num[++sp] = x % 10, x /= 10;
while (sp)
*T++ = num[sp--] + 48;
}
inline ll power(ll x, ll y) {
ll res = 1;
while (y) {
if (y & 1)
res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
inline ll pomod(ll x) {
return power(x, mod - 2);
}
int main() {
fread(buffer, 1, 1 << 28, stdin);
t = read();
while (t--) {
a = read(), b = read(), h = read();
int k = power(b, h);
if (a > b) {
if (b == 1)
write(((a - b)*h % mod + a * k % mod) % mod);
else
write(((a - b) * (k - 1) % mod * pomod(b - 1) % mod + a * k % mod) % mod);
} else
write(a * k % mod);
*T++ = '\n';
}
fwrite(puffer, 1, T - puffer, stdout);
return 0;
}