题意:
对一个数x(A nA n-1A n-2 ... A 2A 1),定义它的权重为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 ",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 ",ans); 64 printf("Case #%d: %d ",++kase,solve(b)); 65 } 66 return 0; 67 }