[题解]UVA12627 奇怪的气球膨胀 Erratic Expansion

思路

这题是一道非常好的递归分治题。

首先我们需要读懂题目。题目说:\(1\) 小时内,\(1\) 红可以变成 \(3\) 红 + \(1\) 蓝,\(1\) 蓝可以变成 \(4\) 蓝,问:第 \(k\) 小时,\(A \sim B\) 行中有几个红。

然后,我们可以预处理一下第 \(k\) 个小时,总共的红气球的数量,即 \(3^k\) 个。

其次,我们定义一个 \(f(k,x)\) 函数,表示第 \(k\) 小时,\(1 \sim x\) 红球的总数。

我们来看一下 \(f\) 函数是怎么实现这个功能的。

这个函数的边界有两个:

  1. \(x \leq 0\) 时,返回 \(0\)
  2. \(k = 0\) 时,返回 \(1\)

这两点想必大家都没有问题。

最重要的地方来了,我们可以将函数分为两种情况。

  1. 如果 \(x\) 在上半部分,即:\(x \leq 2^{k - 1}\),就要返回 \(f(k - 1,x) \times 2\)
  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;  
}  
posted @ 2024-06-27 12:34  WBIKPS  阅读(22)  评论(0)    收藏  举报