題目見
P1990
遞推問題的關鍵是要找到前一次和後一次之間的關係。
只要找到這個關係(或者說,列出表達式),那麼問題已經得到了解決。
這個題目怎樣找到前一次呢?
-
首先 確定一列
i
。集中目光在這一列上。 -
由於有兩種不同的磚,我們要確定上一塊磚的類型
- 條形磚
- L形磚
-
條形磚可以有不同的方向:
- 條形磚可以豎着放:那麼減掉一塊磚,對應的情況就是
i-1
列的完全情況。 - 條形磚可以橫着放:只能放兩塊才能對應到上一個完全情況即
i-2
- 條形磚可以豎着放:那麼減掉一塊磚,對應的情況就是
-
L形磚:
- 如果將底邊對向大端,那麼會出現一個缺格。這個缺格將導致無法彌補的缺陷。即先前的完全情況加上這一塊磚後無論如何不能填滿。
如圖綠色爲完全區域,紅色爲本次操作的磚塊。白色爲缺陷。
- 所以L形磚只能將底邊朝向完全區。但這很快導致了新的問題。需要維護一種新的完全區域。即半滿型。圖示表現了我們的需求:
現在我們就來推導這個遞推關係:
我們在先前的全滿的基礎上可以加L形磚,與這個半滿的尾端兩相對應補成完整的一個2*3矩形,即可得到一個這個半滿數組的一個來源f(i-1)*1
。但還有加條形磚的情況,且只能如圖放置:
我們又找到一個來源,即g(i-1)*1
- 所以我們又得出了關於新數組的遞推式:
g(i) = g(i-1) + f(i-1)
簡單地初始化如下:
#define N 1000000 + 10
int f[N] = {1, 1}, g[N] = {0, 1};
主函數如下:
int main()
{
int n, mod = 10000;
cin >> n;
for (int i = 2; i <= n; i++)
{
f[i] = (f[i-1] + f[i-2] + 2 * g[i-2]) % mod;
g[i] = (g[i-1] + f[i-1]) % mod;
}
cout << f[n];
return 0;
}
總結:
遞推問題要找到每一步的所有可能情況,然後求解來源。