[蓝桥杯 2015 国 C] 机器人繁殖(高精度+数学)

95 篇文章 0 订阅

[蓝桥杯 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=1na12i+1
这个公式的求和,也是很好求的,算出的结果为:
a 1 = S n − n − 1 2 n + 1 − 1 a_1=\frac{S_n-n-1}{2^{n+1}-1} a1=2n+11Snn1
本道题很鸡贼,我们得用高精度。
下面是高精度的好模板:

乘法模板:高精度乘高精度

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;
}
  • 48
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值