定義十進制數 x = AₙAₙ₋₁...A₁ 的權值 F(x) = Aₙ·2ⁿ⁻¹ + Aₙ₋₁·2ⁿ⁻² + ... + A₁·2⁰。給定 A, B (<10⁹),求 0 到 B 中有多少數 x 滿足 F(x) ≤ F(A)。T ≤ 10000。
F(x) 最大值:9 位數全 9 → 9×(2⁹-1) = 4599 < 5500。狀態空間極小。dp[len][firstDigit][weight]:長度 len、最高位 firstDigit、權值和為 weight 的數字個數。sum[len][firstDigit][w] = Σ_{k≤w} dp[len][firstDigit][k] 快速查詢區間個數。dp[0][0][0] = 1;
for (len = 1; len <= 9; len++)
for (first = 0; first <= 9; first++)
for (w = 0; w <= 5000; w++)
for (prev = 0; prev <= 9; prev++)
if (w >= first * (1<<(len-1)))
dp[len][first][w] += dp[len-1][prev][w - first*(1<<(len-1))];
// 構建前綴和 sum[len][first][w]
target = F(A)。digit:0 ~ digit-1,累加 sum[len][d][target]。target -= digit * (1<<(len-1));若 target < 0 提前返回。ans++(B 本身若符合)。#include#include #define MOD 1000000007 int dp[10][10][5500], sum[10][10][5500]; int fac[10] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000}; int main() { // 預計算 dp 和 sum dp[0][0][0] = 1; for (int len = 1; len <= 9; len++) { for (int first = 0; first <= 9; first++) { for (int w = 0; w <= 5000; w++) { int t = 0; for (int prev = 0; prev <= 9; prev++) { int need = w - first * (1 << (len-1)); if (need >= 0) t += dp[len-1][prev][need]; } dp[len][first][w] = t; sum[len][first][w] = (w ? sum[len][first][w-1] : 0) + t; } } } int T; scanf("%d", &T); for (int cs = 1; cs <= T; cs++) { int A, B; scanf("%d%d", &A, &B); int target = 0; for (int i = 9; i >= 1; i--) target += ((A / fac[i-1]) % 10) * (1 << (i-1)); int ans = 0; for (int i = 9; i >= 1; i--) { int d = (B / fac[i-1]) % 10; for (int dig = 0; dig < d; dig++) ans += sum[i][dig][target]; target -= d * (1 << (i-1)); if (target < 0) break; } if (target >= 0) ans++; printf("Case #%d: %d\n", cs, ans); } return 0; }