HDU-4734 F(x) 【数位DP】

Problem Description
For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).
 

 

Input
The first line has a number T (T <= 10000) , indicating the number of test cases.
For each test case, there are two numbers A and B (0 <= A,B < 109)
 

 

Output
For every case,you should output "Case #t: " at first, without quotes. The t is the case number starting from 1. Then output the answer.
 

 

Sample Input
3
0 100
1 10
5 100
 

 

Sample Output
Case #1: 1
Case #2: 2
Case #3: 13
 

 
思路:数位DP
  • dp(i, j)表示枚举到第i位剩余数位权值和不超过j时的数的数量。
  • 记忆化搜索即可。

 

Code:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e5 + 10;
 4 long long dp[15][maxn];
 5 int a[15], temp;
 6 
 7 int f(int x) {
 8     int t = 0, ans = 0;
 9     while(x) {
10         ans += x % 10 * (1 << t);
11         x /= 10;
12         ++t;
13     }
14     return ans;
15 } 
16 
17 long long dfs(int pos, int res, bool limit) {
18     if (res < 0) return 0;
19     if (pos == 0) return 1;
20     if (!limit && ~dp[pos][res]) return dp[pos][res];
21     int up = limit ? a[pos] : 9;
22     long long ans = 0;
23     for (int i = 0; i <= up; ++i)
24         ans += dfs(pos-1, res-i*(1<<(pos-1)), limit && a[pos] == i);
25     if (!limit) dp[pos][res] = ans;
26     return ans;
27 }
28 
29 long long cal(int x) {
30     int len = 0;
31     while(x) {
32         a[++len] = x % 10;
33         x /= 10;
34     }
35     return dfs(len, temp, 1);
36 }
37 
38 int main() {
39     int T, a, b, kase = 0;
40     memset(dp, -1, sizeof(dp));
41     cin>>T;
42     while(T--) {
43         cin>>a>>b;
44         temp = f(a);
45         cout<<"Case #"<<++kase<<": "<<cal(b)<<endl;
46     }
47 
48     return 0;
49 }

posted @ 2017-03-01 16:40  Robin!  阅读(118)  评论(0编辑  收藏  举报