Time Limit: 1000/500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10160 Accepted Submission(s): 4020
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
Source
2013 ACM/ICPC Asia Regional Chengdu Online
Recommend
liuyiding | We have carefully selected several similar problems for you: 6521 6520 6519 6518 6517
思路:减法,dp[pos][sum],sum不是存当前枚举的数的前缀和(加权的),而是枚举到当前pos位,后面还需要凑sum的权值和的个数,
也就是说初始的是时候sum是f(a),枚举一位就减去这一位在计算f(i)的权值,那么最后枚举完所有位 sum>=0时就是满足的,后面的位数凑足sum位就可以了。
仔细想想这个状态是与f(a)无关的(新手似乎很难理解),一个状态只有在sum>=0时才满足,如果我们按常规的思想求f(i)的话,那么最后sum>=f(a)才是满足的条件。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
int fa, A, B, pos, t;
int dp[20][10000], a[20]; // 其中dp[pos][sum]指的是当前位为pos,后面还需要凑sum的权值和的个数,这点及其重要
int f(int x) {
if (!x) return 0;
int ans = f(x / 10);
return ans * 2 + (x % 10);
}
int dfs(int pos, int sum, bool limit) {
if (pos == -1) return (sum <= fa ? 1 : 0);
if (sum > fa) return 0;
if (!limit && dp[pos][fa - sum] != -1) return dp[pos][fa - sum];
int up = limit ? a[pos] : 9;
int ans = 0;
for (int i = 0; i <= up; i++) {
ans += dfs(pos - 1, sum + i * (1 << pos), limit && i == a[pos]);
}
if (!limit) dp[pos][fa - sum] = ans;
return ans;
}
int solve(int x) {
pos = 0;
fa = f(A);
while (x) {
a[pos++] = x % 10;
x /= 10;
}
return dfs(pos - 1, 0, true);
}
int main() {
scanf("%d", &t);
memset(dp, -1, sizeof(dp));
for (int i = 1; i <= t; i++) {
scanf("%d %d", &A, &B);
printf("Case #%d: %d\n", i, solve(B));
}
return 0;
}