题目链接: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;
}