a021 大數運算

大一的時候,只要寫OJ遇到大數,我都是直接用python,因為python支援大數運算,所以所有的大數題目就會變得簡單很多。而我也有用C寫過,加法是最簡單的,減法難了一點點、乘法難了一些但還應付得來,不過除法我就完全束手無策,光是看完做法並轉成code就花了大概八小時。

解題想法:
1.將輸入的x,y字串轉成數字並順序顛倒地存入a,b陣列。
2.加法:一個位數加完就cl++(cl代表數字c有幾位數),進位的時候如果是最大的位數進,cl再+1。
3.減法:先用xBigger函式看ab大小,0表a<b,就讓c=b-a,並在最前面輸出負號;1表y>x,就讓c=b-a,然後直接輸出;2表x=y,直接輸出0。
4.乘法:先乘完所有位數,再一一進位。
5.除法:一樣先用xBigger函式看ab大小,若xBigger()=0就直接輸出0,>0的話就先讓b的位數對齊a,意思就是:

a = 123456
b = 789

在b的最後面加0補齊,讓b的位數等於a的位數。

a = 123456
b = 789000

對齊之後,再來就是除法的部分了,不過我們是用減法來完成。舉7/2為例,直接除可以得到3餘1,用減的話就是7去減2減3次得到1,所以==減的次數就是商==。
那要減多少次呢?就是減到==被除數小於除數為止==,每個位數的商都是用這樣的方式求出,先從最大的位數開始,減到不能減之後就==把除數的最後一個0拿掉==,然後求下一個位數的商,以此類推,做到除數沒有0之後就退出並印出商的值。

這裡我們令a=123456,b=789

a = 123 456
b = 789 000
c = 000 000

b>a,所以商為0,b/=10。

a = 1234 56
b = 0789 00
c = 0000 00

可減1次,所以商為1,b/=10。

a = 04455 6
b = 00789 0
c = 00010 0

可減5次,所以商為5,b/=10。

a = 005106
b = 000789
c = 000150

可減5次,所以商為5,然後b借的0都拿掉了,所以退出並輸出155。

NA (score:89%)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//C
#include<stdio.h>
#include<stdint.h>
#include<string.h>
#define max(x,y) x>y?x:y

int16_t a[505],b[505],c[505],d[505],xBig;

int xBigger(int16_t a[],int16_t b[],int al,int bl){
if(al>bl){return 1;}
else if(al==bl){
for(int i=al-1;i>=0;i--){
if(a[i]<b[i]){return 0;}
else if(a[i]>b[i]){return 1;}
}
return 2;
}
return 0;
}

void sub(int16_t a[],int16_t d[],int al,int dl){
int i;
for(i=0;i<dl;i++){a[i]-=d[i];}
for(i=0;i<al;i++){
if(a[i]<0){a[i]+=10;a[i+1]--;}
}
}

int main(){
char x[505],y[505],op;
scanf("%s %c %s",x,&op,y);
int i,j,cl=0,jin=0;
int al=strlen(x),bl=strlen(y);
for(i=0;i<505;i++){a[i]=0;b[i]=0;c[i]=0;}
for(i=0;i<al;i++){a[al-1-i]=x[i]-48;}
for(i=0;i<bl;i++){b[bl-1-i]=y[i]-48;}
switch(op){
case '+':
for(i=0;i<al||i<bl;i++){
c[i]+=a[i]+b[i];
if(c[i]>=10){
c[i+1]+=c[i]/10;
c[i]=c[i]%10;
if(i==max(x,y)-1){cl++;}
}
cl++;
}
break;
case '-':
if(xBigger(a,b,al,bl)!=2){
if(xBigger(a,b,al,bl)==1){
for(i=0;i<al;i++){c[i]=a[i]-b[i];cl++;}
}
else if(xBigger(a,b,al,bl)==0){
printf("-");
for(i=0;i<bl;i++){c[i]=b[i]-a[i];cl++;}
}
for(i=0;i<cl;i++){
if(c[i]<0){c[i]+=10;c[i+1]--;}
}
if(c[cl-1]==0){cl--;}
}
else{cl=1;}
break;
case '*':
if( (al==1&&a[0]==0) || (bl==1&&b[0]==0) ){cl=1;}
else{
for(i=0;i<bl;i++){
for(j=0;j<al;j++){c[i+j]+=a[j]*b[i];}
}
for(i=0;i<al+bl;i++){
if(c[i]>=10){c[i+1]+=c[i]/10;c[i]=c[i]%10;}
cl++;
}
if(c[al+bl-1]==0){cl--;}
}
break;
case '/':
/*xy比大小*/
if( (al==1&&a[0]==0) || (bl==1&&b[0]==0) ){cl=1;}
else{
if(xBigger(a,b,al,bl)>0){
int dl=al-bl;cl=dl+1; //dl:al,bl差多少位數 cl:預估c有多少位數
for(i=dl;i>=0;i--){
for(j=bl-1;j>=0;j--){d[j+i]=b[j];} //讓b往前移i個位數,並用d儲存。
for(j=0;j<i;j++){d[j]=0;} //把d最後的i個位數用0補齊
while(xBigger(a,d,al,bl+i)>0){
sub(a,d,al,bl+i);
if(a[al-1]==0){al--;} //若a的最大位數變成0,a的位數--。
c[i]++; //每減一次,商+1。
}
for(j=0;j<al;j++){d[j]=0;} //每個位數做完就resetD
}
if(c[cl-1]==0){cl--;} //若c的最大位數變成0,c的位數--。
}
else{cl=1;}
}
break;
}
for(i=cl-1;i>=0;i--){printf("%hd",c[i]);}
printf("\n");
return 0;
}

說了這麼多,這個code在我自己的終端機試了很多測資都能正確執行,但我還是NA了兩次 ,兩次都是8筆測資對7筆,而且兩次錯的小測資都一模一樣,逼得我只好開大絕用python,敲短短地6行就AC。

AC (17ms, 3.4MB)

1
2
3
4
5
6
a,op,b=input().split()
x,y=int(a),int(b)
if(op=='+'):print(x+y)
elif(op=='-'):print(x-y)
elif(op=='*'):print(x*y)
elif(op=='/'):print(x//y)

封面圖源:Pixiv