HDU-4734 F(x)数位dp

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734

大致意思就是每次询问【0,b】区间有多少数的f(i) <= f(a)

这题有一个巧妙的状态定义方式:dp[pos][sum]表示枚举到第pos位,【还需要】sum才能达到f(a)

1e9的数据范围,sum不超过5000。最后只要sum >= 0就表示不超过f(a)

状态依旧与输入的a无关:如果a改变了,dfs传入的sum改变,而枚举pos位得到sum是数本身的性质,所以还是在开头memset

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int a[15], dp[15][5000];
 7 
 8 int f(int k){
 9     int ans = 0, pos = 0;
10     while (k){
11         ans += (k%10)*(1<<pos);
12         k /= 10;
13         pos++;
14     }
15     return ans;
16 }
17 
18 int dfs(int pos, int sum, bool lim){
19     if (pos == -1) return sum >= 0;
20     if (sum < 0) return 0;
21     if (!lim && dp[pos][sum] != -1) return dp[pos][sum];
22     int ans = 0;
23     int r = lim ? a[pos] : 9;
24     for (int i = 0; i <= r; i++){
25         ans += dfs(pos-1, sum - i*(1<<pos), lim && i == a[pos]);
26     }
27     if (!lim) dp[pos][sum] = ans;
28     return ans;
29 }
30 
31 int solve(int k, int b){
32     k = f(k);
33     int pos = 0;
34     while (b){
35         a[pos++] = b % 10;
36         b /= 10;
37     }
38     return dfs(pos-1, k, 1);
39 }
40 
41 int main(){
42     int t, kase = 0, k, b;
43     scanf("%d", &t);
44     memset(dp, -1, sizeof dp);
45     while (t--){
46         scanf("%d%d", &k, &b);
47         printf("Case #%d: %d\n", ++kase, solve(k, b));
48     }
49     return 0;
50 }

 

posted @ 2018-07-24 16:32  QAQorz  阅读(172)  评论(0编辑  收藏  举报