欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

UVa12627 例题8-12 奇怪的气球膨胀

程序员文章站 2022-03-11 23:48:02
...

原文链接:UVA12627


题目大意:

一开始有一个红气球,每小时,一个红气球会变成3个红气球和1个蓝气球,而一个蓝气球会变成4个蓝气球(如图所示)。求经过k小时后,第A~B行一共有多少个红气球?
UVa12627 例题8-12 奇怪的气球膨胀


参考博客:

http://blog.csdn.net/zyq522376829/article/details/46591661


解题思路:

根据题目的类型,理所当然的想到需要用分治的思想。但是一直不知道应该怎么分。后来看了紫书上给的题解之后,看了递推公式之后,感觉好简单。当然要自己想出递推公式却不一定简单。

首先设f(k,i)为k小时之后,上面i行中红气球的数量。则所求气球的数量就是f(k,B) - f(k,A-1),很容易理解。接下来就是f(k,i)怎么求得问题。根据图形可以看出:当i ≥2^(k-1) (也就是i大约等于当前图形的一半长度时),f(k,i)包含了两个k-1时刻的图形(上半部分)和k-1时刻图形的前i-2^(k-1)行。当i<2^(k-1)时,就是k-1时刻图形的前i行包含红气球的2倍,递推公式如下(偷偷的截一张图,哈哈哈哈哈嗝)。

UVa12627 例题8-12 奇怪的气球膨胀
c(k) = 3c(k-1) = 3^k

至于c(k)表示的就是k时刻图形所有红气球的数量,由于每次变化时每个红色的气球都会分裂出三个红色的气球,所以可以知道c(k)=3^k,详细代码如下。

还有另一种递推方法,即令g(k,i)表示为k时刻图形最后i行中红气球的数目,关于g(k,i)的递推公式,我的理解跟紫书上给的有点歧义,所以就没按g的方法写。读者可以自行思考,听说按照g(k,i)写更快一点。


代码:

#include<iostream>
#include<cmath>

using namespace std;

long long f(int k, int r);

int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    int T, kase = 0;
    cin >> T;
    while (T--) {
        int k, a, b;
        cin >> k >> a >> b;
        cout << "Case " << ++kase << ": " << f(k, b) - f(k, a - 1) << endl;
    }
    return 0;
}

long long f(int k, int r)
{
    if (r <= 0) return 0;
    if (k == 0) return 1;       //当k=1时,f(k,r) = 1
    int n = pow(2, k - 1);      
    //当i >= 2^(k-1),f(k,r) = f(k - 1,i - 2^(k-1)) + 2*c(k-1) ,其中c(k) = pow(3,k):每次一个红的都会变成三个
    if (r >= n) return f(k - 1, r - n) + 2 * pow(3, k - 1);
    else return 2 * f(k - 1, r);        //i < 2^(k-1) ,f(k,r) = 2 * f(k-1,r)
}