斐波那契数列——兔子问题

斐波那契数列——兔子问题:

春天来了, 又到了交配的季节。一般而言, 一对兔子在出生一个月后(即出生后的第二个月)就
有了繁殖能力,此后一对兔子每个月能生出一对小兔子来。例如,若最开始有一对刚出生的兔子,
兔子的繁殖如下表所示:
经过月份 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
*/
posted @ 2019-07-19 08:03  DAGGGGGGGGGGGG  阅读(7533)  评论(0编辑  收藏  举报