[题解]UVA12627 奇怪的气球膨胀 Erratic Expansion
思路
这题是一道非常好的递归分治题。
首先我们需要读懂题目。题目说:\(1\) 小时内,\(1\) 红可以变成 \(3\) 红 + \(1\) 蓝,\(1\) 蓝可以变成 \(4\) 蓝,问:第 \(k\) 小时,\(A \sim B\) 行中有几个红。
然后,我们可以预处理一下第 \(k\) 个小时,总共的红气球的数量,即 \(3^k\) 个。
其次,我们定义一个 \(f(k,x)\) 函数,表示第 \(k\) 小时,\(1 \sim x\) 红球的总数。
我们来看一下 \(f\) 函数是怎么实现这个功能的。
这个函数的边界有两个:
- \(x \leq 0\) 时,返回 \(0\)。
- \(k = 0\) 时,返回 \(1\)。
这两点想必大家都没有问题。
最重要的地方来了,我们可以将函数分为两种情况。
- 如果 \(x\) 在上半部分,即:\(x \leq 2^{k - 1}\),就要返回 \(f(k - 1,x) \times 2\)。
- 否则,就要返回 \(f(k - 1,x - 2 ^ {k - 1}) + 2 \times r_{k - 1}\)。
最后,输出的时候用一个类似于前缀和的思路即可。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
int T,opt,k,a,b;
int r[35];
int f(int k,int x){// f 函数
if (x <= 0) return 0;//两个边界
if (k == 0) return 1;
if (x <= 1 << k - 1) return f(k - 1,x) * 2;//两种情况
return f(k - 1,x - (1 << k - 1)) + 2 * r[k - 1];
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
r[0] = 1;//预处理
for (int i = 1;i <= 30;i++) r[i] = r[i - 1] * 3;
cin >> T;
while (T--){
cin >> k >> a >> b;//输入
cout << "Case " << ++opt << ": " << f(k,b) - f(k,a - 1) << endl;//输出
}
return 0;
}

浙公网安备 33010602011771号