[蓝桥杯 2015 国 C] 机器人繁殖
题目描述
X 星系的机器人可以自动复制自己。它们用
1
1
1 年的时间可以复制出
2
2
2 个自己,然后就失去复制能力。
每年X星系都会选出
1
1
1 个新出生的机器人发往太空。也就是说,如果X星系原有机器人
5
5
5 个,
1
1
1 年后总数是:
5
+
9
=
14
5 + 9 = 14
5+9=14
2
2
2 年后总数是:
5
+
9
+
17
=
31
5 + 9 + 17 = 31
5+9+17=31
如果已经探测经过 n n n 年后的机器人总数 s s s,你能算出最初有多少机器人吗?
输入格式
输入一行两个数字 n n n 和 s s s,用空格分开,含义如上。 n n n 不大于 100 100 100, s s s 位数不超过 50 50 50 位。
输出格式
要求输出一行,一个整数,表示最初有机器人多少个。
样例 #1
样例输入 #1
2 31
样例输出 #1
5
样例 #2
样例输入 #2
97 2218388550399401452619230609499
样例输出 #2
8
提示
时限 1 秒, 512M。蓝桥杯 2015 年第六届国赛
思路
通过观察本道题可以知道:我们求的是:
S
n
=
∑
i
=
1
n
a
1
2
i
+
1
S_n=\sum _{i=1}^{n}a_12^i+1
Sn=i=1∑na12i+1
这个公式的求和,也是很好求的,算出的结果为:
a
1
=
S
n
−
n
−
1
2
n
+
1
−
1
a_1=\frac{S_n-n-1}{2^{n+1}-1}
a1=2n+1−1Sn−n−1
本道题很鸡贼,我们得用高精度。
下面是高精度的好模板:
乘法模板:高精度乘高精度
vector<int> mul(vector<int>& A, vector<int>& B) {
vector<int> C(A.size()+B.size()+10,0);
int t=0;
for (int i=0; i<A.size();i++) {
for(int j=0;j<B.size();j++){
C[i+j]+=A[i]*B[j];
}
}
for(int i=0;i<C.size();i++){
t+=C[i];
C[i]=t%10;
t/=10;
}
while (C.size()>1&&C.back()==0) C.pop_back();
return C;
}
除法模板:高精度除高精度
bool cmp(vector<int> A,vector<int> B){
//判断两个大整数大小
if(A.size()!=B.size()) return A.size()>B.size();
for(int i=A.size()-1;i>=0;i--){
if(A[i]!=B[i]) return A[i]>B[i];
}
return true; //判断A是否大于B两个大整数
}
vector<int> sub(vector<int> A,vector<int> B){
int t=0;
vector<int> C;
for(int i=0;i<A.size();i++){
t=A[i]-t;
if(i<B.size())t-=B[i];
C.push_back((t+10)%10);
if(t<0) t=1;
else t=0;
}
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
vector<int> dive(vector<int> A,vector<int> B,vector<int> r){
//减法模拟除法
//求商的位数
r=A;
int lc=A.size()-B.size()+1;
vector<int> C(lc,0);
//计算商的每一位 C[i] r最终为余数 一开始为a
for(int i=lc-1;i>=0;i--){
//商为r-除数的次数 直到小于除数
// 给除数补位和被除数一样
vector<int> tmp(B.size()+i,0);
for(int j=0;j<B.size();j++){
tmp[j+i]=B[j];
}
while(cmp(r,tmp)){
C[i]++; //那么商加加
r=sub(r,tmp); //r-tmp; 继续直到小于
}
}
//去除前导0
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
AC代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
vector<int> add(vector<int> a,vector<int> b){
vector<int>res;
int t=0;
for(int i=0;i<a.size()||i<b.size();i++){
if(i<a.size())t+=a[i];
if(i<b.size())t+=b[i];
res.push_back(t%10);
t/=10;
}
if(t){
res.push_back(1);
}
return res;
}
vector<int> mul(vector<int> a,int b){
int t=0;
vector<int> res;
for(int i=0;i<a.size()||t;i++){
if(i<a.size())t+=a[i]*b;
res.push_back(t%10);
t/=10;
}
return res;
}
bool cmp(vector<int> A,vector<int> B){
//判断两个大整数大小
if(A.size()!=B.size()) return A.size()>B.size();
for(int i=A.size()-1;i>=0;i--){
if(A[i]!=B[i]) return A[i]>B[i];
}
return true; //判断A是否大于B两个大整数
}
vector<int> sub(vector<int> A,vector<int> B){
int t=0;
vector<int> C;
for(int i=0;i<A.size();i++){
t=A[i]-t;
if(i<B.size())t-=B[i];
C.push_back((t+10)%10);
if(t<0) t=1;
else t=0;
}
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
vector<int> dive(vector<int> A,vector<int> B,vector<int> r){
//减法模拟除法
//求商的位数
r=A;
int lc=A.size()-B.size()+1;
vector<int> C(lc,0);
//计算商的每一位 C[i] r最终为余数 一开始为a
for(int i=lc-1;i>=0;i--){
//商为r-除数的次数 直到小于除数
// 给除数补位和被除数一样
vector<int> tmp(B.size()+i,0);
for(int j=0;j<B.size();j++){
tmp[j+i]=B[j];
}
while(cmp(r,tmp)){
C[i]++; //那么商加加
r=sub(r,tmp); //r-tmp; 继续直到小于
}
}
//去除前导0
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
int n;
vector<int>A,B,C,D,E,F,G;
int main(){
cin>>n;
n++;
string a,b;
cin>>a;
b=to_string(n);
for(int i=a.size()-1;i>=0;i--){
A.push_back(a[i]-'0');
}
for(int i=b.size()-1;i>=0;i--){
B.push_back(b[i]-'0');
}
F.push_back(1);
D.push_back(1);
C=sub(A,B);
while(n--){
D=mul(D,2);
}
D=sub(D,F);
E=dive(C,D,G);
E=add(E,F);
for(int i=E.size()-1;i>=0;i--){
cout<<E[i];
}
return 0;
}