第六届蓝桥杯国赛:机器人繁殖从公式推导到C++/Python的实现

题目 1831: 机器人繁殖

时间限制: 1Sec 内存限制: 128MB 提交: 883 解决: 227

题目描述

X星系的机器人可以自动复制自己。它们用1年的时间可以复制出2个自己,然后就失去复制能力。
每年X星系都会选出1个新出生的机器人发往太空。也就是说,如果X星系原有机器人5个,
1年后总数是:5 + 9 = 14
2年后总数是:5 + 9 + 17 = 31

如果已经探测经过n年后的机器人总数s,你能算出最初有多少机器人吗?

输入

输入一行两个数字n和s,用空格分开,含义如上。n不大于100,s位数不超过50位。

输出

要求输出一行,一个整数,表示最初有机器人多少个。

样例输入

2 31

样例输出

5

思路

我们很容易发现,对于这一道题目,是有迹可循的,对于此我们可以简单的进行分析。

首先我们规定以下符号:

n:年数 s:机器人总数 k:最初的机器人数量

  1. 首先我们先看一下题目,其中我们可以发现:
    第 n 年 所 能 产 生 的 机 器 人 个 数 = 2 ∗ 第 ( n − 1 ) 年 所 能 产 生 的 机 器 人 个 数 − 1 第n年所能产生的机器人个数 = 2*第(n-1)年所能产生的机器人个数-1 n=2(n1)1
    那么我们将这个公式进行推广,通过数学归纳法可以得到这样的一个公式:
    第 n 年 所 能 产 生 的 机 器 人 个 数 = 2 n k − 2 n + 1 第n年所能产生的机器人个数 = 2^{n}k-2^{n}+1 n=2nk2n+1
    这个公式不难理解,原因也很简单,每年新增人数如下:
    n = 0 : k n = 1 : k + ( k − 1 ) n = 2 : k + ( k − 1 ) + ( k − 1 ) + ( k − 2 ) . . . . . . n = m : k + ( k − 1 ) + ( k − 1 ) + ( k − 2 ) + ( k − 2 ) + ( k − 3 ) . . . . . . ( k − m − 1 ) + ( k − m ) n=0:k\\ n=1:k+(k-1)\\ n=2:k+(k-1)+(k-1)+(k-2)\\ ......\\ n=m:k+(k-1)+(k-1)+(k-2)+(k-2)+(k-3)......(k-m-1)+(k-m) n=0:kn=1:k+(k1)n=2:k+(k1)+(k1)+(k2)......n=m:k+(k1)+(k1)+(k2)+(k2)+(k3)......(km1)+(km)
    我们很容易发现k前的系数是2{n-1} 而后面的偏置就是系数-1。

  2. 接下来我们在推导一下机器人总数s:

    我们知道机器人总数s不过就是每年新增人数之和,故:
    s = ∑ i = 1 n ( 2 i k − 2 i + 1 ) + 1 s = ( 2 n + 1 − 1 ) k − ( 2 n + 1 − 1 ) + n + 1 s = \sum_{i=1}^n(2^{i}k-2^{i}+1)+1\\ s = (2^{n+1}-1)k-(2^{n+1}-1)+n+1 s=i=1n(2ik2i+1)+1s=(2n+11)k(2n+11)+n+1

  3. 那么当这个等式出来以后,我们就可以惊奇的发现,整个题目都变成了一个三元方程,后面我们只需要把这个方程解出来即可,唯一需要注意的可能就是关于大数除法的问题了。为了方便计算,我们把等式稍微变形一下:
    s − n − 1 = ( 2 n + 1 − 1 ) ( k − 1 ) s-n-1 = (2^{n+1}-1)(k-1) sn1=(2n+11)(k1)

代码描述

python

string = input('')
n = int(string.split()[0])
s = int(string.split()[1])
k = (s-n-1)/(2**(n+1)-1)+1
print(int(k))

C++

#include
#include
using namespace std;
int main(){
    //需要注意,这里可能会用到大数运算,但非常神奇的就是这里的double居然不会出错
    double s;
    int n, k;
    cin >> n >> s;
    k = (s-n-1)/(pow(2, n+1) -1) +1;
    cout << k;
    return 0;
}

你可能感兴趣的:(算法)