斐波那契數列——兔子問題:
春天來了, 又到了交配的季節。一般而言, 一對兔子在出生一個月后(即出生后的第二個月)就
有了繁殖能力,此后一對兔子每個月能生出一對小兔子來。例如,若最開始有一對剛出生的兔子,
兔子的繁殖如下表所示:
經過月份 0 1 2 3 4 5 6 7
幼崽對數 1 0 1 1 2 3 5 8
成兔對數 0 1 1 2 3 5 8 13
總對數 1 1 2 3 5 8 13 21
現在,在原問題的基礎上假設每對兔子都會在產下第 m 對后代后死亡,其中 m 是一個確定的
數,問經過 n 個月后有多少對兔子。注意衰老的兔子在產下第 m 對兔子后立即死亡,不算入該月
總體對數統計,例如當 n = 10, m = 5 時,我們有:
經過月份 0 1 2 3 4 5 6 7 8 9 10
幼崽對數 1 0 1 1 2 3 5 7 12 18 29
1 歲成兔對數 0 1 0 1 1 2 3 5 7 12 18
2 歲成兔對數 0 0 1 0 1 1 2 3 5 7 12
3 歲成兔對數 0 0 0 1 0 1 1 2 3 5 7
4 歲成兔對數 0 0 0 0 1 0 1 1 2 3 5
5 歲成兔對數 0 0 0 0 0 1 0 1 1 2 3
總對數 1 1 2 3 5 8 12 19 30 47 74
注意答案可能非常大,所以請對 1000000007 取模。
斐波那契數列——兔子問題是經典的遞推題,但是如果考慮兔子會死的情況呢。
假設一只兔子產m代之后會死,也就是以
當現在還沒有到m+1代時,有:
\(dp[i]=dp[i-1]+dp[i-2]\)
正好在m+1月時,需要減去第1個月的那一對。
而在\(>=m+2\)月時,
有\(dp[i] = dp[i - 1] + dp[i - 2] - dp[i - m - 2]\);
可是為什么是\(-dp[i-m-2]\),由於我們記\(dp[i]\)為i時刻還活着的兔子。
而當i為活着的右區間時,\(i-(m+1)\)是左區間。
所以求前綴和的時候要減\(i-(m+1)-1\)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1e9+7;
int dp[1001000] = {1, 1, 2};
int s[100100];
signed main()
{
int n, m, ans = 0;
int T;
// freopen("B.in", "r", stdin);
// freopen("B.out", "w", stdout);
scanf("%lld", &T);
while (T--)
{
int ans = 0, temp = 0;
scanf("%lld%lld", &n, &m);
m = min(m, n);
for (int i = 2; i <= n; i++)
{
if (i <= m)
dp[i] = ( (dp[i - 1] % mod) + (dp[i - 2] % mod) + mod) % mod;
else if (i == m + 1)
dp[i] = ( (dp[i - 1] % mod) + (dp[i - 2] % mod) - (dp[1] % mod) + mod ) % mod;
else
dp[i] = ( (dp[i - 1] % mod) + (dp[i - 2] % mod) - (dp[i - m - 2] % mod) + mod) % mod ;
}
printf("%lld\n", dp[n] % mod);
}
}
/*
2
5 10
8 5
*/