HDU 4734 F(x)

题目链接:HDU 4734 F(x)

题目大意:
定义十进制数(x)的权值为(F(x)=A_n imes 2^{n-1}+A_{n-1} imes 2^{n-2}+...+A_2 imes 2+A_1 imes 1)(A(i))表示十进制数(x)中第(i)位的数字。
题目给出(A)(B),求出([0,B])有多少个权值不大于(F(A))的数。

题解:
(dp[pos][sum])表示长度为(pos)且权值不大于(sum)的数的个数。
用记忆化搜索,到最低位若权值仍小于(F(A))则表示该数符合。

#include <cstring>
#include <iostream>
using namespace std;
#define ll long long

int digit[20];
ll dp[20][5000], n, m;

int dfs(int pos, int sum, bool limit) {
    if (pos <= 0) return sum >= 0;
    if (sum < 0) return 0; // 已经比F(A)小了就不用往下搜索了
    if (!limit && dp[pos][sum] != -1) return dp[pos][sum]; // 没限制则用记忆化搜索
    int ans = 0;
    int up = limit ? digit[pos] : 9;
    for (int i = 0; i <= up; ++i) {
        ans += dfs(pos - 1, sum - i * (1 << (pos - 1)), limit && i == up);
    }
    if (!limit) dp[pos][sum] = ans;
    return ans;
}

ll F(ll x) { // F(A)
    ll ans = 0, cnt = 1;
    while (x) {
        ans += x % 10 * cnt;
        cnt *= 2;
        x /= 10;
    }
    return ans;
}

int cal(ll x) {
    int cnt = 0;
    while (x) {
        digit[++cnt] = x % 10;
        x /= 10;
    }
    return cnt;
}

int main() {
    int T;
    cin >> T;
    memset(dp, -1, sizeof(dp));
    for (int Case = 1; Case <= T; ++Case) {
        cin >> n >> m;
        cout << "Case #" << Case << ": " << dfs(cal(m), F(n), true) << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/IzumiSagiri/p/14315374.html