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

LA 6529 Eleven:數位 DP 計算可被 11 整除的排列數

     編輯:關於C++

LA 6529 Eleven 詳解

題目:給定數字字符串(長度 ≤100),可任意排列。求有多少種排列形成的數能被 11 整除。結果模 10⁹+7。數字可重複,排列視為不同(即使數字相同,位置不同視為不同排列)。

核心數學:11 的整除規則 + 奇偶位和

10 ≡ -1 (mod 11) ⇒ 10ᵏ ≡ (-1)ᵏ (mod 11)。
數字 dₖ...d₁d₀ 模 11 等價於 Σ (-1)ᵏ dₖ。即 奇數位和 - 偶數位和 ≡ 0 (mod 11)。
設總長 n,奇數位個數 odd = (n+1)/2,偶數位 even = n/2。
問題轉化為:從多重集合中選 odd 個數字放奇數位,其餘放偶數位,使 (sum_odd - sum_even) % 11 == 0。

DP 狀態定義

dp[i][j][k]:處理完數字 0..i-1,已放入奇數位 j 個數字,(奇數位和 - 偶數位和) % 11 = k 的方案數。
i ∈ [0,10],j ∈ [0, odd],k ∈ [0,10]。

轉移:枚舉當前數字 i 放入奇數位的個數

設數字 i 出現 cnt 次。枚舉放入奇數位 x ∈ [0, min(cnt, odd-j)],偶數位放 cnt-x。
貢獻差值:delta = (x - (cnt-x)) * i = (2x - cnt) * i。
組合數:選奇數位置 C(odd-j, x),選偶數位置 C(even-(processed-x), cnt-x)。
轉移:

dp[i+1][j+x][(k+delta)%11] += dp[i][j][k] * C(odd-j, x) * C(even-(tot-j), cnt-x)

其中 tot 為已處理總數字數。

去除前導零

總方案含前導零情況。若數字 0 存在,強制最高位(奇數位第 1 位)不為 0:
先減去 1 個 0,對長度 n-1 跑相同 DP 得 ans2。
答案 = (ans1 - ans2) % MOD。

參考代碼邏輯 (C++)

const int MOD = 1e9+7;
long long C[105][105];
long long dp[11][105][11];
int digitCnt[10];

void initComb() {
    for (int i = 0; i <= 100; ++i) {
        C[i][0] = C[i][i] = 1;
        for (int j = 1; j < i; ++j)
            C[i][j] = (C[i-1][j-1] + C[i-1][j]) % MOD;
    }
}

long long solve(int len) {
    memset(dp, 0, sizeof(dp));
    dp[0][0][0] = 1;
    int odd = (len + 1) / 2;
    int processed = 0;
    for (int d = 0; d <= 9; ++d) {
        int cnt = digitCnt[d];
        for (int j = 0; j <= odd && j <= processed; ++j) {
            for (int x = 0; x <= cnt && j+x <= odd; ++x) {
                int delta = ((2*x - cnt) * d) % 11;
                if (delta < 0) delta += 11;
                long long ways = C[odd - j][x] * C[len - processed - (odd - j)][cnt - x] % MOD;
                for (int k = 0; k < 11; ++k) {
                    int nk = (k + delta) % 11;
                    dp[d+1][j+x][nk] = (dp[d+1][j+x][nk] + dp[d][j][k] * ways) % MOD;
                }
            }
        }
        processed += cnt;
    }
    return dp[10][odd][0];
}

int main() {
    initComb();
    string s;
    while (cin >> s) {
        memset(digitCnt, 0, sizeof(digitCnt));
        for (char c : s) digitCnt[c-'0']++;
        long long ans1 = solve(s.size());
        long long ans2 = 0;
        if (digitCnt[0] > 0) {
            digitCnt[0]--;
            ans2 = solve(s.size() - 1);
            digitCnt[0]++;
        }
        cout << (ans1 - ans2 + MOD) % MOD << '\n';
    }
    return 0;
}

關鍵點總結

  1. 11 整除規則轉化:奇偶位和差模 11,將排列問題轉化為選擇奇數位子集問題。
  2. DP 維度:數字種類(10) × 奇數位已選數(≤50) × 模11餘數(11) = 5500 狀態,極小。
  3. 組合數預處理:C[n][k] 用於計算位置選擇方案數。
  4. 前導零處理:總方案 - 最高位固定為 0 的方案(遞歸同結構)。

複雜度分析

指標複雜度說明
時間O(10 · odd · 11 · maxCnt)~幾萬次操作,極快
空間O(10 · odd · 11)DP 表

總結

LA 6529 是「數位 DP + 組合數學 + 同餘理論」的綜合題。它巧妙利用 11 的整除規則將排列計數問題降維為子集選擇問題,再用 DP 統計方案數。此模式可推廣至其他模數(如 3, 9, 7, 13 等)的類似問題,核心在於找到「位置權重模數週期性」並構造相應 DP 狀態。

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