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 }