当数字过大,会存在超过范围而导致无法做运算,所以采取字符串的方法去模拟
,模拟手动做运算的过程。
在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: 大数相乘
题目描述
计算AB
输入
连续输入
输入字符串A和B
A和B分别代表一个正整数(保证A和B不超过3104位)
输出
输出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 ,先给2补0,补到200和a的长度相等,然后300-200=100,100小于200,然后记录相减次数为1,这是抹去一个0,变为100/20,然后做相减操作,100-20等于80,变为80/20,然后再相减变为60/20,再做相减,一直相减直到小于20,最后变为0/20,0小于20,这时记录相减次数为5次,然后抹去0,变为0/2,从200变为了原来的2,就结束,这时的相减次数为0,所以每一位的相减次数分别为1,5,0。得到答案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 2 用2去乘前面的结果
n=3 6 用3去乘前面的结果
n=4 4 2 用4去乘前面的结果(4乘6为24,先存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;
}