# 題目: UVa 12627 - Erratic Expansion
# 題目說明
一開始有一顆紅氣球,每過 1 小時,紅氣球會變成 3 顆紅氣球與 1 顆藍氣球、藍氣球會變成 4 顆藍氣球
求過了 k 小時後,從第 a 行到第 b 行的氣球數和
INPUT:
第一行輸入一個整數 t ,代表測資數
每筆測資輸入三個整數 k 、 a 、 b ,代表過了 k 小時,行數 a 與 b
OUTPUT:
輸出過了 k 小時後,從第 a 行到第 b 行的氣球數和
# 解題方法
假設以下公式 dfs(k, i) 為過了 k 小時後,最下面 i 行的氣球數和第a行到第b行的氣球數和 可視為 第a行到最後一行的氣球數和 - 第b + 1行到最後一行的氣球數和
所以可以寫成 dfs(k, n - a + 1) - dfs(k, n - b)
n 為總行數
假設 k = 3 、 a = 3 、 b = 7n 則為 2^3 = 8
上述的算式可以寫成 dfs(3, 8 - 3 + 1) - dfs(k, 8 - 7)
化簡為 dfs(3, 6) - dfs(3, 1)
再由以下關係,計算出紅氣球的總數
當 i >= 2^(k - 1) 時, dfs(k, i) = dfs(k - 1, i - 2^(k - 1)) * 2 + 3^(k - 1)
當 i < 2^(k - 1) 時, dfs(k, i) = dfs(k -1, i)
寫成 recursive 後即可求出答案
同樣以假設 k = 3 、 a = 3 、 b = 7 為例
上面步驟做到 dfs(3, 6) - dfs(3, 1)
首先先處理 dfs(3, 6)
由於 i = 6 >= 2^(k - 1) = 4 ,所以 dfs(3, 6) = dfs(3 - 1, 6 - 2^(3 - 1)) * 2 + 3^(3 - 1) = dfs(2, 2) * 2 + 3^2
這時候 recursive 呼叫 dfs(2, 2) ,由於 i = 2 >= 2^(k - 1) = 2 ,所以 dfs(2, 2) = dfs(2 - 1, 2 - 2^(2 - 1)) * 2 + 3^(2 - 1) = dfs(1, 0) * 2 + 3
這時候 recursive 呼叫 dfs(1, 0) , dfs(1, 0) 回傳 0 ,所以 dfs(2, 2) 回傳 0 * 2 + 3 = 3
最後 dfs(3, 6) 回傳 3 * 2 + 9 = 15
再處理 dfs(3, 1)
由於 i = 1 < 2^(k - 1) = 4 ,所以 dfs(3, 1) = dfs(2, 1)
這時候 recursive 呼叫 dfs(2, 1) ,由於 i = 1 < 2^(k - 1) = 2 ,所以 dfs(2, 1) = dfs(1, 1)
這時候 recursive 呼叫 dfs(1, 1) ,回傳 1 , dfs(2, 1) 回傳 1 ,所以最後 dfs(3, 1) 也回傳 1
dfs(3, 6) - dfs(3, 1) 結果為 15 - 1 = 14
需要使用 long long 不然會爆
# 參考程式碼
#include <iostream> | |
#include <math.h> | |
using namespace std; | |
static auto fast_io = [] | |
{ | |
ios::sync_with_stdio(false); | |
cout.tie(nullptr); | |
cin.tie(nullptr); | |
return 0; | |
}(); | |
long long dfs(int k, long long i) | |
{ | |
if (i == 0) return 0; | |
if (k == 0) return 1; | |
long long n = 1 << (k - 1); | |
return (i >= n ? 2 * dfs(k - 1, i - n) + pow(3, k - 1) : dfs(k - 1, i)); | |
} | |
int main() | |
{ | |
int t, k, a, b, Case = 0; | |
cin >> t; | |
while (t--) | |
{ | |
cin >> k >> a >> b; | |
long long n = 1 << k; | |
cout << "Case " << ++Case << ": " << dfs(k, n - a + 1) - dfs(k, n - b) << "\n"; | |
} | |
} |
# 參考資料
https://www.twblogs.net/a/5e505f33bd9eee2117beb0b7