UVA - 12627

Erratic Expansion

原文PDF鏈接

description:

Piotr found a magical box in heaven. Its magic power is that if you place any red balloon inside it then, after one hour, it will multiply to form 3 red and 1 blue colored balloons. Then in the next hour, each of the red balloons will multiply in the same fashion, but the blue one will multiply to form 4 blue balloons. This trend will continue indefinitely.

The arrangements of the balloons after the 0-th, 1-st, 2-nd and 3-rd hour are depicted in the following diagram.
這裏寫圖片描述

As you can see, a red balloon in the cell (i, j) (that is i-th row and j-th column) will multiply to produce 3 red balloons in the cells (i ∗ 2 − 1, j ∗ 2 − 1), (i ∗ 2 − 1, j ∗ 2), (i ∗ 2, j ∗ 2 − 1) and a blue balloon in the cell (i ∗ 2, j ∗ 2). Whereas, a blue balloon in the cell (i, j) will multiply to produce 4 blue balloons in the cells (i ∗ 2 − 1, j ∗ 2 − 1), (i ∗ 2 − 1, j ∗ 2), (i ∗ 2, j ∗ 2 − 1) and (i ∗ 2, j ∗ 2). The grid size doubles (in both the direction) after every hour in order to accommodate the extra balloons. In this problem, Piotr is only interested in the count of the red balloons; more specifically, he would like to know the total number of red balloons in all the rows from A to B after K-th hour.

Input

The first line of input is an integer T (T < 1000) that indicates the number of test cases. Each case contains 3 integers K, A and B. The meanings of these variables are mentioned above. K will be in the range [0, 30] and 1 ≤ A ≤ B ≤ 2 K.

Output

For each case, output the case number followed by the total number of red balloons in rows [A, B] after K-th hour.

Sample Input

3
0 1 1
3 1 8
3 3 7

Sample Output

Case 1: 1
Case 2: 27
Case 3: 14


題目大意:
按照某個規律依次生成一個氣球方陣,簡單的說就是,每次增加4倍的大小,其中左上方,右上方,左下方都和上一個的方陣一樣,有下方全爲藍色氣球。現在告訴我們第k個方陣,讓我們求從第A行到第B行共有幾個紅色氣球。
                          

解題思路:
1.紅色氣球數量的規律挺好找的,用f(k,i) 表示第k個方陣第i行有幾個紅色氣球。那麼有:
方陣的上半區:f(k,i) = 2 * f(k-1,i)
方陣的下半區:f(k,i) = f(k-1,i- 2k1 )
然後就很自然的想到用一個數組記錄,以減少遞歸中的重複計算,但是如果要記錄的話需要30 * 2^30 大小的數組,這顯然是不現實的。而直接遞歸求每一行再累加的話肯定會超時。(遞歸調用的次數太多了)

2.其實我們也很明顯的發現在計算的過程中進行了大量的重複計算,那麼怎麼做減少計算次數呢?

3.第K個方陣的紅色氣球總數是很好算的,就是 3^K 。(下一個方陣的紅色氣球總數就是前一方陣的3倍嘛)而大的部分方陣總能化簡爲幾個小的完整方陣的和。那麼我們求第A行到第B行紅色氣球數量可以改爲求前B行的氣球總數減去前A-1行的氣球數量。

核心代碼:

long long fun(int K, int n) {
    if (n == 0)        //這個表示前一次計算正好是一個完美的上半方陣
        return 0;
    if (K == 0)       
        return 1;
    int temp = 1 << (K - 1);
    if (n >= temp)    //所求的部分方陣包含了整個上半方陣
        return fun(K - 1, n - temp) + 2 *num[K-1];
    else
        return 2 * fun(K - 1, n);
}

4.這個時候,我們對一開始發現的規律已經做一個修改。此時f(k,i)的含義是第K個方陣前i行的紅色氣球總數。
方陣的上半區:f(k,i) = 2 * f(k-1,i)
方陣的下半區:f(k,i) = f(k-1,i- 2k1 ) + 2*3k1


源代碼

#include <iostream>  
#include <stdio.h>    
#include <cstring>  
#include <string>  
using namespace std;

long long num[31];

long long fun(int K, int n) {
    if (n == 0)
        return 0;
    if (K == 0)
        return 1;
    int temp = 1 << (K - 1);
    if (n >= temp) 
        return fun(K - 1, n - temp) + 2 *num[K-1];
    else
        return 2 * fun(K - 1, n);
}

int times;
int k, a, b;
int main() {
    num[0] = 1;
    for (int i = 1; i<30; i++)
        num[i] = 3 * num[i - 1];
    scanf("%d", &times);
    for (int i = 0; i < times; i++) {
        scanf("%d%d%d", &k, &a, &b);
        printf("Case %d: %lld\n", i+1, fun(k,b)-fun(k,a-1));
    }
    system("pause");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章