高精度计算 大数相乘+模拟

当数字过大,会存在超过范围而导致无法做运算,所以采取字符串的方法去模拟
,模拟手动做运算的过程。
在32位编译器下
1个字节8位

int 4个字节
long 4 个字节
long long 8个字节
_int64 8个字节
double 8个字节
long double 12个字节
unsigned int 4个字节
unsigned long 8个字节

问题 A: 大数相加

题目描述
计算A+B
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过5*106位)
输出
输出A+B
样例输入
2222222222222222222222
1111111111111111111111111
样例输出
1113333333333333333333333

#include <cstring>//c++ 版
#include <iostream>
#include <algorithm>
using namespace std;
string ans;
string num_push(string a,string b){
	ans.clear();
  int lena=a.size();
  int lenb=b.size();
  reverse(a.begin(),a.end());  //翻转a
  reverse(b.begin(),b.end());  //翻转b
  int yu=0;  //余数
  for(int i=0;;i++){    //一直跑
    if(i<lena&&i<lenb){    //如果小于a的长度,并且小于b的长度
      ans+=(yu+a[i]-'0'+b[i]-'0')%10+'0';  //第几位等于a的数值加上b的数值
      yu=(yu+a[i]-'0'+b[i]-'0')/10;  //然后再求余数
    }else if(i<lena){          //如果只小于a,说明b跑完了
      ans+=(yu+a[i]-'0')%10+'0';  //只需加上a的数值加上之前的余数
      yu=(yu+a[i]-'0')/10;  
    }else if(i<lenb){          
      ans+=(yu+b[i]-'0')%10+'0';
      yu=(yu+b[i]-'0')/10;
    }else if(yu!=0){   //都跑完了余数还不为零那么再进一位
      ans+=yu%10+'0';
      yu=yu/10;
    }else break; //然后退出
  }
  reverse(ans.begin(),ans.end());  //最后翻转一下
  return ans;
}
string a,b;
int main(){
  while(cin>>a>>b){
    cout<<num_push(a,b)<<endl;
  }
  return 0;
}

问题 B: 大数相减

题目描述
计算A-B
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过1*105位)
输出
输出A-B
样例输入
222222222222222222222222222
1
样例输出
222222222222222222222222221

#include<bits/stdc++.h>
using namespace std;
const int maxn=100000;
char a[maxn],b[maxn];
char ans[maxn];
char* strrev(char* s)
{
    /* h指向s的头部 */
    char* h = s;
    char* t = s;
    char ch;
    /* t指向s的尾部 */
    while(*t++){};
    t--;    /* 与t++抵消 */
    t--;    /* 回跳过结束符'\0' */
    /* 当h和t未重合时,交换它们所指向的字符 */
    while(h < t)
    {
        ch = *h;
        *h++ = *t;    /* h向尾部移动 */
        *t-- = ch;    /* t向头部移动 */
    }
    return(s);
}

int judge(char *a,char *b){
  int lena=strlen(a);
  int lenb=strlen(b);
  if(lena>lenb) return 1;
  else if(lena<lenb) return -1;
  else return strcmp(a,b);  //相等返回0;
}

char *solve(char *a,char *b){
    char aa[maxn],bb[maxn];
    memset(aa,0,sizeof(aa));  //aa始终存大的
    memset(bb,0,sizeof(bb)); //bb始终存小的
    memset(ans,0,sizeof(ans));  //初始化
    char *as=ans; //定义指针
    bool fuhao=false;  //定义负号
    int cnt=judge(a,b); //判断大小
    if(cnt>0){ //如果a大于b
      strcpy(aa,a);
      strcpy(bb,b);
      fuhao=false;
    }
    else if(cnt<0){
      strcpy(aa,b);
      strcpy(bb,a);
      fuhao=true;
    }
    else {
      ans[0]='0';
      return as;
    }
     int lena=strlen(aa);
     int lenb=strlen(bb);
     strrev(aa);
     strrev(bb);
     int i;
     for(i=0;;i++){
       if(i<lena&&i<lenb){
                if(aa[i]>=bb[i]){
                   ans[i]=aa[i]-bb[i]+'0';
                 }
                else {
                        ans[i]=aa[i]-bb[i]+10+'0';
                           for(int j=i+1;;j++){ //借位
                                 if(aa[j]=='0') aa[j]='9';
                                 else{
                                   aa[j]--;
                                   break;
                                  }
                           }
                }
      }
      else if(i<lena){
          ans[i]=aa[i];
      }else if(i<lenb){
          ans[i]=bb[i];
      }else break;
  }
    while(i--){
        ans[i+1]='\0';  //置为空格
        if(ans[i]-'0'>0)
        break;
    }
      if(fuhao) ans[i+1]='-';  //最后判断是否添加负号
      strrev(ans);
      return as;
}

int main(){
while(~scanf("%s %s", a, b)){
    printf("%s\n", solve(a,b));
  }
  return 0;
}

问题 C: 大数相乘

题目描述
计算A
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过3
104位)
输出
输出A*B
样例输入
22222222222222222222222222 1
样例输出
22222222222222222222222222

#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100000
int ans[maxn];
string num;
string num_mul(string a,string b){
  memset(ans,0,sizeof ans);
  num.clear();
  int lena=a.size();
  int lenb=b.size();
  reverse(a.begin(),a.end());
  reverse(b.begin(),b.end());
  for(int i=0;i<lena;i++){
    for(int j=0;j<lenb;j++){  //b的每一位乘a的每一位
      ans[i+j]+=(a[i]-'0')*(b[j]-'0');
    }
  }
  int yu=0; //初始余数为0
  int i;
  int len=lena+lenb-1;  //总长度
  for(i=0;;i++){    //转化
    if(i<len||yu!=0){   //小于总长或者还有余数时 
      yu=ans[i]+yu; 
      ans[i]=yu%10; //数值等于模十
      yu=yu/10;  //余数等于除十
    }else break;   
  }
  while(i--){
    num+=ans[i]+'0';
  }
  return num;
}
string a,b;
int main(){
  while(cin>>a>>b){
    cout<<num_mul(a,b)<<endl;
  }
  return 0;
  }

问题 D: 大数相除

题目描述
计算:
A÷B = C
A % B = D
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过1*103位)
输出
A÷B = C (向下取整)
A % B = D
样例输入
22222222222222222222222222 2
样例输出
11111111111111111111111111
0

大数除法的模拟用减法去模拟,除法可以用减法去表示,相减的次数就是除法的值
但是当10000000000/1时就要相减10000000000次,这样就会超时
所以我们做每一位的减法,如300/2=150,百位相减一次,十位相减5次,个位相减0次
那如何对每一位进行相减呢。
比如a/b,先给b末位补零b,直到a和b的长度相等,变为b1,然后用a去减b1,直到a小于b1了,存储相减次数,这时给b1抹去一个0,再做相减,如此循环做上述操作,直到b1变为原来的b
如300/2 ,先给20,补到200和a的长度相等,然后300-200=100100小于200,然后记录相减次数为1,这是抹去一个0,变为100/20,然后做相减操作,100-20等于80,变为80/20,然后再相减变为60/20,再做相减,一直相减直到小于20,最后变为0/200小于20,这时记录相减次数为5次,然后抹去0,变为0/2,从200变为了原来的2,就结束,这时的相减次数为0,所以每一位的相减次数分别为150。得到答案150


#include<bits/stdc++.h>
using namespace std;
 string ans;
 string anss;
 string yu;
int judge(string a,string b){  
  int lena=a.size(); //string 的大小使用size()  字符数组使用strlen()
  int lenb=b.size();
  if(lena>lenb) return 1;   //判断长度,如果a长度大于b,直接返回1
  else if(lena<lenb) return -1;//如果a长度小于b,直接返回-1
  else if(a>b) return 1;
  else if(a<b) return -1;
  else if(a==b) return 0;  //长度一样的情况下。字符串比较
}

string num_mul(string a,string b){
  string aa;  //aa始终存大的
  string bb;  //bb始终存小的
  bool fuhao=false;
  aa.clear();
  bb.clear();
  ans.clear();
  int cnt=judge(a,b);
  if(cnt==1){ //cnt=1说明a比b大
     aa=a;
     bb=b;
     fuhao=false;
  }else if(cnt==-1){
     aa=b;
     bb=a;
     fuhao=true;
  }else{
    ans+='0'; //一样时直接返回0
    return ans;
  }
  reverse(aa.begin(),aa.end());
  reverse(bb.begin(),bb.end());
  int lena=aa.size(); //string 的大小使用size()  字符数组使用strlen()
  int lenb=bb.size();
  int i;
   for(i=0;;i++){
       if(i<lena&&i<lenb){  //如果i即小于a的长度又小于b的长度
            if(aa[i]>=bb[i]){   //如果这一位的数值大于等于这一位,则直接减
               ans+=aa[i]-bb[i]+'0';
            }else{              //如果小于,则需要借位
               ans+=aa[i]-bb[i]+10+'0'; //减了之后加10
               for(int j=i+1;;j++){   //先前借位
                  if(aa[j]=='0') aa[j]='9';  //碰到 0需要再向前借位
                  else{
                    aa[j]--;  //否则只需借的位减一
                    break; //退出借位循环
                  }
               }
            }
       }else if(i<lena){
         ans+=aa[i];
       }else if(i<lenb){
         ans+=bb[i];
       }
       else break;
   }
   while(i--){  //减法后存在前几位翻转后为0的情况所以需要删除
     if(ans[i]-'0'>0)
        break;   //找到位置退出
   }
   ans.erase(i+1,lena-i);  //删除0
   if(fuhao) ans+='-'; //如果为负,加负号
   reverse(ans.begin(),ans.end());
   return ans;
}

string num_div(string a,string b){   //a除b
  anss.clear();
  int lena=a.size();
  int lenb=b.size();
  for(int i=lenb;i<lena;i++)
     b+='0';
  while(lena-->=lenb){  //上下做减法,减到a的长度小于0了,b摸去个0  求的是每一位的减法
    int i=0;  //该位相减次数先置0
    while(judge(a,b)>=0){
      a=num_mul(a,b);
      i++;  //该位相减次数加1
    }
    anss+=(i+'0');  //该位相减次数入anss
    b.erase(lena); //抹去个零  lena有--
  }
  yu=a;
  if(anss.size()==0){
     anss+='0';
     return anss;
   }
   if(anss[0]=='0'){
     anss.erase(0,1);
   }
   return anss;
}

string a,b;
int main(){
    while(cin>>a>>b){
        cout<<num_div(a,b)<<endl;
  			cout<<yu<<endl;
    }
return 0;
}

问题 E: 计算N!

题目描述
给定一个整数N( 0 <= N <= 10000),你的任务是计算它的阶乘。
输入
输入包含多组测试样例,每组测试样例包含一个整数n。
输出
对于每个N,输出N的阶乘。
样例输入
1
2
3
样例输出
1
2
6

首先题目给出n最大为10000,这做阶乘肯定会爆掉,所以用字符串去模拟

      ans(ans存结果)string类型
n=1   1
n=2   22去乘前面的结果
n=3   63去乘前面的结果
n=4   4 24去乘前面的结果(4624,先存4,然后有进位2,再加一位存2)
以此类推


#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000;
int tot,ans[maxn];

int main(){
  int n;
  while(cin>>n){
    memset(ans,0,sizeof(ans));
    ans[0]=1;
    tot=1;//进位位置
    int now,cnt;//now为要存放的位置cnt为进位
    for(int i=2;i<=n;i++){ //直接命n=1时结果为1,然后从2开始走
        now=0;cnt=0;
        while(now<tot){
          int t=ans[now]*i+cnt;//这一位的总值
          ans[now++]=t%10;  //值为总值模10
          cnt=t/10; //余数为总值除10
          if(now==tot&&cnt) tot++; 
        }
    }
    for(int i=tot-1;i>=0;i--){
      cout<<ans[i];
    }
    cout<<endl;
  }
}

问题 F: 数字除法

题目描述
给你一个整数N,你可以执行如下操作,
1:如果N能被2整除,用N/2代替N。
2:如果N能被3整除,用2N/3代替N。
3: 如果N能被5整除 用4N/5代替N。
你的任务是通过上述操作,求出将N变成1所需要的最小操作次数。
输入
输入第一行一个数字q,代表询问次数,1 < q < 100。
接下来q次询问,每次询问给出一个整数N 1 <= N <= 10^18。
输出
对于每次询问,输出一个数并换行,如果能从N到1输出最小操作次数,否则输出 -1。
样例输入
7
1
10
25
30
14
27
1000000000000000000
样例输出
0
4
6
6
-1
6
72

#include<bits/stdc++.h>
using namespace std;
int main(){
  int q,cnt;
  long long int n;
  while(cin>>q){
    while(q--){
        cnt=0;
        cin>>n;
        while(1){
             if(n%2==0){
                n=n/2;
                 cnt++;
             }else if(n%3==0){
                n=(n/3)*2;
                 cnt++;
             }else if(n%5==0){
                n=(n/5)*4;
                 cnt++;
             }else if(n==1)
                break;
             else{
               cnt=-1;break;
             }
          }
        if(cnt>=0) cout<<cnt<<endl;
        else cout<<"-1"<<endl;
  }
}

问题 G: 神奇的数字基因

题目描述
众所周知,人类的外观与外貌具有极大的差异性,但实际决定其各种因素的根本因素在于基因,而实际上,同种生物的全部基因库相似性其实相当的高。而数字长相上差异性也是很大的,但数字的大小取决于它的基因,也就是说相同大小的数字基因是相等的。羊村的新村长帆洋洋对数字很感兴趣,尤其是对于数字之间基因的关系,他给希望你能够写一个程序帮助他判断数字 A 与 B 的基因关系,如果你能帮助村长帆洋洋成功找出数字间的基因关系,羊村将会俸你为贵客,还有希望能见到羊村的村花美羊羊哦! 你可以帮助帆洋洋嘛?只需要写出一个能够判断A和B是否相等的程序哦

Data range: (1e -10000 <= A ,B <= 1e10000)
输入
测试可能包含多个样本。
每个测试用例包含两个数字A和B。
输出
对于每一种情况,如果A等于B,你应该打印“YES”,否则打印“NO”。
样例输入
1 2
3 3
4 3
21 21
1.00 1.0
样例输出
NO
YES
NO
YES
YES
提示
1.00 和 1.0
001 和 1 都相等哦

即去除前置无用0和后置无用0
#include <cstdio>
#include <cstring>
using namespace std;

void cut(char * a) {  //切掉后置无用0
  int la = strlen(a)  - 1;
  for (int i = la; i > 0; i-- ) {
    if (a[i] == '0') 
       la--;
    else break;
  }
  if (a[la] == '.') 
      la--;
   a[la + 1] = '\0';
}

int main() {
  char a[50000], b[50000];

  while (scanf("%s%s", a, b) != EOF) {
    int la = strlen(a);
    int lb = strlen(b);
    for (int i = 0 ; i < la; i++ ) {
     	 if (a[i] == '.') {
      		cut(a);
      		break;
      	}
    }

    for (int i = 0 ; i < lb; i++ ) {
      if (b[i] == '.') {
      	cut(b);
      	break;
      }
  }
  //切掉无用前置0
    char * p1 = a, * p2 = b;  //用指针的方法切
    int t = 0;
    while (a[t] == '0') 
        t++;
    p1 = p1 + t;
     t = 0;
    while (b[t] == '0') 
        t++;
    p2 = p2 + t;

    if (strcmp(p1, p2)) printf("NO\n");
    else printf("YES\n");
  }

return 0;
}

问题 H: 刘莎莎的作业

题目描述
快帮数学不好的刘莎莎解决这个问题吧
得到一个正整数n,请输出有几个正整数k满足 k^k ≤ n
输入
测试用例不超过50个
每种情况只包含一行中的正整数n
1 ≤ ñ ≤ 10^18
输出
对于每个测试用例,输出一个整数表示正整数k满足k^k ≤ n的k的数量
样例输入
5
19
28
样例输出
2
2
3

方法一:k^k<=n 可以两边取对数变为k*log(k)<=log(n),这样就能很快算出来了
#include<bits/stdc++.h>
using namespace std;

int main(){
  long long int n;
   int flag;
  while(cin>>n){
    flag=0;
    for(int i=1;i<=n;i++){
      if(i*log(i)<=log(n)){
        flag++;
      }
      else break;
    }
    cout<<flag<<endl;
  }
}
方法二
#include<stdio.h>
 
int main(){
    long long int n, num, i;
    long long int sum[20]; 
    //因为大致到15时,15的15次方就能超过题所给的n的最大值,所以整个数组直接存下来这前十五位的情况
    for(i = 1; i <= 15; i++){
            num = 1;
           for(j = 1; j <= i; j++) 
              num *= i;
           sum[i] = num;
    }
    while(~scanf("%lld", &n)) {
         for(i=1; i<16; i++){
            if(sum[i]<=n);  //比较然后直接输出坐标
            else break;
        }
        printf("%lld", i-1);
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值