[算法]牛的繁殖问题(python)

牛的繁殖问题

题目地址

问题描述

Description

Cows in the FooLand city are interesting animals. One of their specialties is related to producing offsprings. A cow in FooLand produces its first calve (female calf) at the age of two years and proceeds to produce other calves (one female calf a year).

Now the farmer Harold wants to know how many animals would he have at the end of N years, if we assume that none of the calves die, given that initially, he has only one female calf?

explanation:At the end of 1 year, he will have only 1 cow, at the end of 2 years he will have 2 animals (one parent cow C1 and other baby calf B1 which is the offspring of cow C1).At the end of 3 years, he will have 3 animals (one parent cow C1 and 2 female calves B1 and B2, C1 is the parent of B1 and B2).At the end of 4 years, he will have 5 animals (one parent cow C1, 3 offsprings of C1 i.e. B1, B2, B3 and one offspring of B1).

Input

The first line contains a single integer T denoting the number of test cases. Each line of the test case contains a single integer N as described in the problem.

Output

For each test case print in new line the number of animals expected at the end of N years modulo 10^9 + 7.

Sample Input 1

2
2
4

Sample Output 1

2
5
题目解析

就是求一个斐波那契数列中的某个数,只是这个数会很大,使用传统的方式会超时

思路解析

可以参考:洛谷题目解析

这里有两种方法

矩阵快速幂

斐波那契数列化成矩阵形式表达,有如下式子,(不理解的话乘一下就知道了)

[ F n − 1 F n − 2 ] × [ 1 1 1 0 ] = [ F n F n − 1 ] \left[\begin{array}{ccc}F_{n-1} & F_{n-2}\end{array}\right] \times \left[\begin{array}{ccc} 1 & 1 \\ 1 & 0 \end{array}\right] = \left[ \begin{array}{ccc}F_n & F_{n-1} \end{array}\right] [Fn1Fn2]×[1110]=[FnFn1]

因此:

当n<2时,直接返回F2或F1即可,

当n>2时

定 义 初 始 矩 阵 ans = [ F 2 F 1 ] = [ 1 1 ] , base = [ 1 1 1 0 ] 定义初始矩阵\\ \text{ans} = \left[\begin{array}{ccc}F_2 & F_1\end{array}\right] = \left[\begin{array}{ccc}1 & 1\end{array}\right], \text{base} = \left[\begin{array}{ccc} 1 & 1 \\ 1 & 0 \end{array}\right] ans=[F2F1]=[11],base=[1110]
那 么 , F n 就 等 于 ans × base n − 2 这 个 矩 阵 的 第 一 行 第 一 列 元 素 , 也 就 是 [ 1 1 ] × [ 1 1 1 0 ] n − 2 的 第 一 行 第 一 列 元 素 。 那么,F_n 就等于 \text{ans} \times \text{base}^{n-2}这个矩阵的第一行第一列元素,\\也就是 \left[\begin{array}{ccc}1 & 1\end{array}\right] \times \left[\begin{array}{ccc} 1 & 1 \\ 1 & 0 \end{array}\right]^{n-2} 的第一行第一列元素。 Fnans×basen2[11]×[1110]n2
也 就 是 b a s e n − 2 的 第 一 列 元 素 之 和 也就是{base}^{n-2}的第一列元素之和 basen2

公式法

利用Fibonacci递推公式:

F[2n] = F[n+1]² - F[n-1]² = (2F[n-1] + F[n]) · F[n] ①

F[2n+1] = F[n+1]² + F[n]² ②

利用map来暂时存储所需要的数据,即记录结果

代码实现(python)

快速幂

mod = 10 ** 9 + 7

def m_pow(cur, base): # 计算矩阵乘法
    a1 = (cur[0][0] * base[0][0] + cur[0][1] * base[1][0]) % mod
    a2 = (cur[0][0] * base[0][1] + cur[0][1] * base[1][1]) % mod
    b1 = (cur[1][0] * base[0][0] + cur[1][1] * base[1][0]) % mod
    b2 = (cur[1][0] * base[0][1] + cur[1][1] * base[1][1]) % mod
    res = [[a1, a2], [b1, b2]]
    return res

# 1 1 2 3 5 8 13 
if __name__ == '__main__':
    d = {1: 1, 2: 1}
    for _ in range(int(input())): 
        n = int(input()) + 1 
        if n < 2:
            print(d[n])
        else: # 以下类似于普通快速幂
            res = [[1, 0], [0, 1]]  # 初始化结果矩阵,类似于快速幂中的ans
            base = [[1, 1], [1, 0]]  # 初始化base矩阵,类似于快速幂中的a
            n = n - 2  
            while n > 0:
                if n & 1 == 1:  # 奇数
                    res = m_pow(res, base)
                # 偶数
                n = n // 2
                base = m_pow(base, base)
            ans = (res[0][0] + res[1][0]) % mod #求和
            print(ans)

公式法

mod = 1000000007
d = {1: 1, 2: 1}


def fib(n):
    if n < 3:
        return d[n]

    if n in d:
        return d[n]

    if (n % 2 == 1):
        k = (n + 1) // 2
        x = (fib(k) * fib(k) + fib(k - 1) * fib(k - 1)) % mod
        d[n] = x # cache

    else:
        k = n // 2
        x = (fib(k) * ((fib(k + 1) * 2) - fib(k))) % mod
        d[n] = x
    return d[n] # cache


for _ in range(int(input())):
    n = int(input())
    print(fib(n + 1))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值