輸入 N (N ≤ 1000? 實測需支援更大),輸出 N! 完整十進制表示。多組測試資料至 EOF。
int data[50000] 陣列儲存十進制位(低位在前,data[0] 為個位)。len 記錄有效位數。operator= (const char*) 字串賦值、operator* (int) 整數乘法、print() 輸出。BigNumber BigNumber::operator*(int a) {
BigNumber z;
int q = 0; // 進位
int i;
for (i = 0; i < len; ++i) {
int p = data[i] * a + q;
z.data[i] = p % 10;
q = p / 10;
}
while (q) { // 處理最高位進位
z.data[i++] = q % 10;
q /= 10;
}
z.len = i;
z.clearLeadZero();
return z;
}
memset(data, 0, sizeof(data))。否則舊資料殘留導致高位垃圾值參與運算。for(i=0; i<len; ++i) 後直接 z.len=i 而省略 while(q) 會導致最高位進位丟失(如 99*99=9801,若無 while 只得 801)。data[i] = str[len-i-1]-'0',便於低位對齊運算。#include <cstdio>
#include <cstring>
const int NMAX = 50000;
struct BigNumber {
int data[NMAX];
int len;
BigNumber() : len(1) { memset(data, 0, sizeof(data)); }
BigNumber& operator=(const char* str) {
memset(data, 0, sizeof(data));
len = strlen(str);
for (int i = 0; i < len; ++i)
data[i] = str[len - i - 1] - '0';
return *this;
}
BigNumber operator*(int a) const {
BigNumber z;
long long q = 0; // 用 long long 防乘法溢位
int i = 0;
for (; i < len; ++i) {
long long p = 1LL * data[i] * a + q;
z.data[i] = p % 10;
q = p / 10;
}
while (q) {
z.data[i++] = q % 10;
q /= 10;
}
z.len = i;
while (z.len > 1 && !z.data[z.len - 1]) --z.len;
return z;
}
void print() const {
for (int i = len - 1; i >= 0; --i) putchar('0' + data[i]);
putchar('\n');
}
};
int main() {
int N;
while (scanf("%d", &N) == 1) {
BigNumber ans = "1";
for (int i = 2; i <= N; ++i) ans = ans * i;
ans.print();
}
return 0;
}
log10(N!) ≈ N log10 N,N=10000 約 35660 位,NMAX=50000 足夠。| 錯誤 | 後果 | 修正 |
|---|---|---|
| 賦值未清零 | 高位殘留導致結果隨機錯誤 | memset(data,0,sizeof(data)) |
| 乘法進位處理不完整 | 最高位進位丟失(如 25! 錯誤) | 保留 while(q) 迴圈 |
int p = data[i]*a+q 溢位 | data[i]≤9, a≤10000, q≤... 32位int足夠,但長乘法建議 long long | 用 long long 計算中間值 |
| 輸出前未去除前導零 | 如 00120 | clearLeadZero() 或輸出前 while 迴圈 |
HDU 1042 是高精度乘法的經典入門題。掌握「十進制陣列 + 逐位乘法 + 進位傳播 + 前導零清理」模板,可輕鬆解決階乘、斐波那契、大數加減乘除等系列問題。關鍵在於細節:賦值清零、進位完整處理、中間值防溢位。建議將此模板封裝為通用 BigInt 類,支援任意大小整數運算,作為後續 ACM/ICPC 競技的基礎組件。