蓝桥杯真题 机器人繁殖【第六届】【决赛】【C组】(C语言实现)

        注意!!!本题只讲思路,代码不一定正确!!

        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

  再例如:
  用户输入:
  97 2218388550399401452619230609499

  则程序应该输出:
  8

思路:

这是一道数学题,首先给你一个基础的底数x,然后再在这个x的基础上计算。(记住这个x,很重要)

按照题目要求,我们要做的是从结果来算出这个x。

那我们就得从结果和x的关系入手,前面也说了,这是个数学题,所以最后我们能推出来x和结果的一个关系式,然后做一个逆运算就能得出答案。

接下来开始推公式:

首先,我们先引入一个n作为第几年,然后我们假设x = 5 。

按照题目要求,先繁殖增加一倍,然后再向太空发射一个,也就是减一。

所以第一年繁殖了2 * 5 - 1个机器人,也就是9个。

       第二年繁殖了2 * 9 - 1个机器人,也就是17个。

       第三年繁殖了2 * 17 - 1个机器人,也就是33个。

以此类推,我们可以算出每一年增加的机器人数量,那么最终结果就是每一年的机器人之和。

那这与结果和x之间有什么关系呢?

我们可以将每一年繁殖个数用一个函数 f(t) 来表示。

那么上面的式子就能写成

第一年     2 * 5 - 1 = f(1);

第二年     2 * f(1) - 1 = f(2);

第三年     2 * f(2) - 1 = f(3) ........

以此类推。

那么最终,我们能得到的机器人总数就是

f(1) + f(2) + f(3) + ......+ f(n)

由于这边我们后一年繁殖个数和前一年有关系,所以我们可以将这个式子全部用f(1)来代替

第一年是 f(1);

第二年是 2 * f(1) - 1;

第三年是 2 * (2 * f(1) - 1) - 1 化简就是 4 * f(1) - 3;

第四年是 2 * ( 4 * f(1) - 3) - 1 化简就是8 * f(1) - 7;

这样我们就能将最终结果用有关f(1)来表示了

那么这怎么和x扯上关系呢?

别忘了f(1)从哪里来,2 * x - 1 = f(1)

所以我们可以继续改写

第零年 x (也就是一开始)

第一年 2 * x - 1;

第二年 2 * (2 * x - 1) - 1 化简就是4 * x - 3;

第三年 2 * (4 * x - 3) - 1 化简就是8 * x - 7;

第四年 2 * (8 * x - 7) - 1 化简就是16 * x - 15;

有没有发现这里面的规律

我们可以看到x的系数可以写作2^n(n代表第几年)

                     后面一项可以写成2^n - 1

也就是说我们可以得出x与每一年繁殖量之间的关系式

f(n) = \begin{cases} x , &n = 0\\ (2^n*x) - (2^n - 1) ,& n \geq 1\\ \end{cases} 

那么最终结果我们也可以用含n与x的表达式来写出来

首先我们求当n>=1时,总繁殖数怎么算

我们可以将f(n)拆成两部分一部分时(2^n * x) , 另一部分是(2^n - 1)。

我们分别对这两部分求和,然后相减,就能得出答案

首先看第一部分

我们其实只用计算系数就行了

这时就用到了高中的数学知识,等比数列的求和公式

我们能很轻易求出来第一部分和的公式

(2^{n+1} - 2) * x

然后再求第二部分和的公式

同样也是等比数列的求和公式,只不过这次多了一个减一。

(2^{n+1} - 2) - n

然后相减,最终公式就是

f(x) = (2^{n+1} - 2) * x - ((2^{n+1} - 2) - n)

x表示开始底数,n表示几年

公式的出来了

最后结果就是做一个逆运算

x = \frac{ f(x) + ((2^{n+1} - 2) - n)}{(2^{n+1} - 2)}

接下来用代码实现就行了

代码

#include <stdio.h>
long long qiu_yuan(long long , long long);
long long qiu_mi(long long);
long long mi(long long);
int main (void)
{
	long long n , zong;
	scanf("%lld%lld" , &n , &zong);
	printf("%lld\n" , qiu_yuan(n , zong));
	return 0;
}

long long mi(long long cs)
{
	long long ans = 1LL;
	long long di  = 2LL;
	while(cs)
	{
		if(cs & 1)
		{
			ans *= di;
		}
		cs /= 2;
		di *= di;
	}
	return ans;
}

long long qiu_mi(long long sz)
{
	long long i;
	long long sum = 0LL;
	for(i = 1LL;i <= sz;i ++)
	{
		sum += mi(i);
	}
	return sum;
}

long long qiu_yuan(long long n , long long z)
{
	z -= n + 2;
	z += mi(n + 1);
	long long mi_zong = qiu_mi(n) + 1;
	return z / mi_zong;
}

这里代码就不赘述了,因为我觉得如果要正常写对得用高精度的算法,我实在是懒得写,所以就直接用long long来写了,但是在蓝桥的oj上居然能过!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值