注意!!!本题只讲思路,代码不一定正确!!
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(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与每一年繁殖量之间的关系式
那么最终结果我们也可以用含n与x的表达式来写出来
首先我们求当n>=1时,总繁殖数怎么算
我们可以将f(n)拆成两部分一部分时(2^n * x) , 另一部分是(2^n - 1)。
我们分别对这两部分求和,然后相减,就能得出答案
首先看第一部分
我们其实只用计算系数就行了
这时就用到了高中的数学知识,等比数列的求和公式
我们能很轻易求出来第一部分和的公式
然后再求第二部分和的公式
同样也是等比数列的求和公式,只不过这次多了一个减一。
然后相减,最终公式就是
x表示开始底数,n表示几年
公式的出来了
最后结果就是做一个逆运算
接下来用代码实现就行了
代码
#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上居然能过!