首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

HDU 1042 N! 大數階乘:C++ 高精度乘法實作與避坑指南

     編輯:關於C語言

題目大意

輸入 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;
}

關鍵避坑點(原碼註釋強調)

  1. 賦值運算子必須先清零:memset(data, 0, sizeof(data))。否則舊資料殘留導致高位垃圾值參與運算。
  2. 乘法迴圈不能合併進位處理:原碼嘗試 for(i=0; i<len; ++i) 後直接 z.len=i 而省略 while(q) 會導致最高位進位丟失(如 99*99=9801,若無 while 只得 801)。
  3. 字串賦值時反序存儲:data[i] = str[len-i-1]-'0',便於低位對齊運算。

完整可編譯代碼(C++11)

#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 足夠。
  • 時間:O(N × 位數) ≈ O(N² log N),N=10000 约 3.5e8 基本操作,C++ 1-2 秒內可通過。
  • 優化方向:基數 1e9 (int32) 或 1e18 (int64) 減少位數、FFT 乘法 (O(N log N)),但本題十進制輸出通常十進制基數最直接。

常見錯誤總結

錯誤後果修正
賦值未清零高位殘留導致結果隨機錯誤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 計算中間值
輸出前未去除前導零如 00120clearLeadZero() 或輸出前 while 迴圈

結語

HDU 1042 是高精度乘法的經典入門題。掌握「十進制陣列 + 逐位乘法 + 進位傳播 + 前導零清理」模板,可輕鬆解決階乘、斐波那契、大數加減乘除等系列問題。關鍵在於細節:賦值清零、進位完整處理、中間值防溢位。建議將此模板封裝為通用 BigInt 類,支援任意大小整數運算,作為後續 ACM/ICPC 競技的基礎組件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved