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

HDU 3709 Balanced Number:數位 DP 求力矩平衡數字個數

     編輯:關於C++

題目大意

稱一個數為「平衡數」,若存在某位 pos 使得左側數字 × 距離之和 = 右側數字 × 距離之和(力矩平衡)。給定區間 [L, R] (R ≤ 10¹⁸),求區間內平衡數個數。

數位 DP 狀態設計

dp[pos][pivot][torque]:正在處理第 pos 位(從低位向高位),平衡點固定為 pivot,已處理低位產生的力矩和為 torque(左側為正,右側為負),滿足條件的方案數。
轉移:枚舉當前位 d (0..9),新力矩 torque + (pos - pivot) * d。若 torque < 0 剪枝(右側力矩過大無法被左側抵消)。
邊界:pos == -1 時 torque == 0 返回 1,否則 0。

枚舉平衡點

數字長度 ≤ 19,平衡點 pivot 可為 0~18。對每個 pivot 獨立跑 DP,結果求和。注意全 0 的情況會被多次計算(每個 pivot 都算一次),需減去 len-1 次重複。

C++ 代碼

#include 
using namespace std;
typedef long long LL;
int bit[20];
LL dp[20][20][1500]; // pos(0..18), pivot(0..18), torque(0..1458=9*18*9)
int targetPivot;

LL dfs(int pos, int torque, bool limit) {
    if (pos == -1) return torque == 0;
    if (!limit && dp[pos][targetPivot][torque] != -1) return dp[pos][targetPivot][torque];
    int up = limit ? bit[pos] : 9;
    LL ans = 0;
    for (int d = 0; d <= up; ++d) {
        int nTorque = torque + (pos - targetPivot) * d;
        if (nTorque < 0) continue; // 剪枝
        ans += dfs(pos-1, nTorque, limit && d==up);
    }
    if (!limit) dp[pos][targetPivot][torque] = ans;
    return ans;
}

LL solve(LL x) {
    if (x < 0) return 0;
    int len = 0;
    if (x == 0) bit[len++] = 0;
    while (x) { bit[len++] = x%10; x/=10; }
    LL ans = 0;
    for (int p = 0; p < len; ++p) {
        targetPivot = p;
        ans += dfs(len-1, 0, false);
    }
    ans -= len - 1; // 扣除 0 的重複計算
    return ans;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    memset(dp, -1, sizeof(dp));
    int T; cin >> T;
    while (T--) {
        LL L, R; cin >> L >> R;
        cout << solve(R) - solve(L-1) << '\n';
    }
    return 0;
}

關鍵點

  • 力矩範圍:最大 9 * 18 * 9 = 1458,DP 表 [20][20][1500] 足夠。
  • targetPivot 全局變量避免傳參開銷。
  • 剪枝 nTorque < 0:右側力矩為負且絕對值過大,後續高位只能增加左側力矩(正),無法平衡。
  • 0 的處理:solve(0)=1,區間查詢用 solve(R) - solve(L-1)。

總結

HDU 3709 是「數位 DP + 自定義物理約束(力矩)」的經典題。核心模板:枚舉關鍵參數(平衡點)+ 狀態攜帶累積物理量(力矩)+ 記憶化遞歸 + 物理剪枝。同套路解決 HDU 3709、Codeforces 數位 DP 物理約束問題。

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