加法
P1601 A+B Problem(高精)
#include<iostream>using namespace std;
const int N = 1e6 + 10;
int a[N],b[N],c[N];
int len1,len2,lenMax; //長度要提前定義在全局,在函數中要使用 void add(int c[],int a[],int b[])
{for(int i=0;i<lenMax;i++){c[i] += a[i] + b[i]; //這里一定是+= ,因為要加上 上一位 給的進位值 c[i + 1] = c[i] / 10; //先處理進位,給下一個位置c[i] %= 10; //再取模存入c[i] }//處理整體進位后結果長度要+1if(c[lenMax]) lenMax++;
}int main()
{string s1,s2;cin >> s1 >> s2;len1 = s1.length(), len2 = s2.length();lenMax = max(len1,len2);for(int i=0;i<len1;i++) a[i] = s1[len1-1-i] - '0';for(int i=0;i<len2;i++) b[i] = s2[len2-1-i] - '0';add(c,a,b); //a數組、b數組相加的結果放在c數組 for(int i=lenMax-1;i>=0;i--) cout << c[i]; return 0;
}
減法
P2142 高精度減法
#include<iostream>using namespace std;
const int N = 1e6 + 10;
int a[N],b[N],c[N];
int la,lb,lc;bool cmp(string& x,string& y) //如果第一個參數小就返回true
{if(x.size() != y.size()){return x.size() < y.size();}else{return x < y;}
}void sub(int c[],int a[],int b[])
{for(int i=0;i<lc;i++){c[i] += a[i] - b[i];if(c[i] < 0){c[i + 1] -= 1; //c[i+1] = -1;c[i] += 10;}}while(lc > 1 && c[lc-1] == 0 ) lc--; //lc最多減到1
}int main()
{string x,y;cin >> x >> y;if(cmp(x,y)) {swap(x,y); //確保x比y大,因為等會要用大數減小數cout << "-"; //交換了說明題目給的是大數減小數,結果為負數 }la = x.length(); lb = y.length(); lc = max(la,lb);//轉化成數組形式 注意減去字符'0' for(int i=0;i<la;i++) a[i] = x[la-1-i] - '0';for(int i=0;i<lb;i++) b[i] = y[lb-1-i] - '0';//執行減法 sub(c,a,b); //輸出c數組結果for(int i=lc-1;i>=0;i--) cout << c[i]; return 0;
}
注意:在消除前導0的時候 while(lc > 1 && c[lc-1] == 0 ) lc--;
該語句中的while
不能改為if
,雖然我們知道減法頂多會讓較大的那個數字減少一位,所以可能就想這條語句頂多執行一次,但是如果這被減數和減數相等,那么減完的結果全部是0,這個時候必須要用while循環去除所有的0
。
乘法
P1303 A*B Problem
#include <iostream>
using namespace std;const int N = 1e6 + 10;
int a[N],b[N],c[N];
int la,lb,lc;void mul(int c[],int a[],int b[])
{//兩層循環模擬列豎式相乘的過程 i和j位置的數相乘結果存在c數組的i+j位置for(int i=0;i<la;i++){for(int j=0;j<lb;j++){c[i+j] += a[i] * b[j]; //無進位乘法,最后處理進位 } }//處理進位 for(int i=0;i<lc;i++){c[i+1] += c[i] / 10; c[i] %= 10;}//處理前導零while(lc > 1 && c[lc-1] == 0) lc--;
}int main()
{string x,y;cin >> x >> y;la = x.size(); lb = y.size(); lc = la + lb; //相乘的結果的最大長度是兩個因數的長度和 for(int i=0;i<la;i++) a[i] = x[la-1-i] - '0';for(int i=0;i<lb;i++) b[i] = y[lb-1-i] - '0';mul(c,a,b);for(int i=lc-1;i>=0;i--) cout << c[i]; return 0;
}
除法
P1480 A/B Problem
#include<iostream>
using namespace std;const int N = 1e6 + 10;int a[N],b,c[N];
int la,lc;typedef long long LL; //t有可能超intvoid div(int c[],int a[],int b)
{LL t = 0; //用來存每一位除完的余數for(int i = la - 1;i >= 0;i--) //從最高位開始處理,所以從la-1開始遍歷{t = t * 10 + a[i];c[i] = t / b;t %= b; }while(lc > 1 && c[lc - 1] == 0) lc--;
}int main()
{string x;cin >> x >> b;la = x.size(); lc = la; //結果和被除數的長度是相同的,只不過結果可能出現前導0,最后處理for(int i = 0;i < la;i++) a[i] = x[la - i - 1] - '0';div(c,a,b);for(int i = lc - 1;i >= 0;i--) cout << c[i];return 0;
}
Q:為什么a要從高位開始處理還要倒著存?
A:方便記憶模板,四種高精度都是倒著存,而且方便處理前導0,處理的方式與其他的高精度都一樣。但是正著存就要從數組的左邊開始處理前導0,而且輸出結果的時候還需要確定范圍。
這是a正著存的模版:
#include<iostream>
using namespace std;const int N = 1e6 + 10;int a[N], b, c[N];
int la, lc;typedef long long LL; void div(int c[], int a[], int b)
{LL t = 0; // 用來存每一位除完的余數for(int i = 0; i < la; i++) // 這里應該是i++,不是i--{t = t * 10 + a[i];c[i] = t / b;t %= b; }// 處理前導零int k = 0;while(k < la && c[k] == 0) k++; // 找到第一個非零位lc = la - k;// 將結果前移for(int i = 0; i < lc; i++)c[i] = c[i + k];
}int main()
{string x;cin >> x >> b;la = x.size();for(int i = 0; i < la; i++) a[i] = x[i] - '0';div(c, a, b);// 輸出結果for(int i = 0; i < lc; i++) cout << c[i];if(lc == 0) cout << "0"; // 處理結果為0的情況return 0;
}