hdu 4734 F(x)

题意:

对一个数x(A nn-1n-2 ... A 21),定义它的权重为F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 1。

现在给出A和B,要求计算出0到B的比区间内有多少个数字的权重不超过A的权重。

思路:

数位dp。

一开始定义dp[pos][sum]表示处理到第pos位,前缀和为sum的数字的个数,每次输入都需要清空dp数组,所以tle了。

其实这个dp的状态是与输入的A有关系的,但是数位dp的本质是与输入的具体数字无关,只与数字的某些状态和特征有关。

所以改变一下dp的状态,用dp[pos][sum]表示从第0位到第pos位小于等于sum的数字有多少,这样就与输入的数字没有关系了。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 int p[15];
 6 int dp[15][1<<13];
 7 int c[15];
 8 int ans;
 9 int cal(int x)
10 {
11     int cnt = 0;
12     int res = 0;
13     while (x)
14     {
15         res += (x % 10) * p[cnt];
16         x /= 10;
17         cnt++;
18     }
19     return res;
20 }
21 int dfs(int pos,int lim,int sta)
22 {
23     if (sta < 0) return 0;
24     if (pos == -1) return 1; 
25     int mx = lim ? c[pos] : 9;
26     if (!lim && dp[pos][sta] != -1) return dp[pos][sta];
27     int res = 0;
28     for (int i = 0;i <= mx;i++)
29     {
30         int cur = sta - i * p[pos];
31         //printf("pos = %d,cur = %d\n",pos,cur);
32         //if (cur > ans) continue;
33         res += dfs(pos-1,lim && i == mx,cur);
34     }
35     if (!lim) return dp[pos][sta] = res;
36     return res;
37 }
38 int solve(int x)
39 {
40     int cnt = 0;
41     while (x)
42     {
43         c[cnt++] = x % 10;
44         x /= 10;
45     }
46     int res = dfs(cnt-1,1,ans);
47     return res;
48 }
49 int main()
50 {
51     p[0] = 1;
52     for (int i = 1;i < 15;i++) p[i] = 2 * p[i-1];
53     int t;
54     scanf("%d",&t);
55     int kase = 0;
56     memset(dp,-1,sizeof(dp));
57     //solve(1000000000);
58     while (t--)
59     {
60         int a,b;
61         scanf("%d%d",&a,&b);
62         ans = cal(a);
63         //printf("%d\n",ans);
64         printf("Case #%d: %d\n",++kase,solve(b));
65     }
66     return 0;
67 }

 

posted @ 2018-05-12 14:46  qrfkickit  阅读(196)  评论(0编辑  收藏  举报