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
题意: 每组数据给出a,b,求[0,b]区间内小于等于f(a)的数字个数。f(x) = An * 2^n-1 + An-1 * 2^n-2 + ... + A2 * 2 + A1 * 1,Ax为十进制下各位数字。
分析: 显然是道数位dp题,可以定义dp数组为dp[15][10000],dp[i][j]表示枚举到第i位,f(a)减第i位之前的权值加和为j时符合条件的数字个数,这样即使不同数据下f(a)改变了也仍然可以用到之前记录的dp值,dp数组只需要一开始初始化一次即可。而定义dp第二维含义为第i位之前的权值加和为j就是错误的,这样要么每组数据前清空dp数组,要么dp数组开第三维记录当前的f(a),显然分别会导致TLE和MLE。
具体代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int c[15], dp[15][10000], a, b;//dp[i][j]表示fa减前i位权值和为j时符合条件的数字个数
int dfs(int pos, int sum, int flag)
{
if(pos == 0)
return 1;
if(flag && dp[pos][sum] != -1)
return dp[pos][sum];
int ans = 0, up = flag ? 9 : c[pos];
for(int i = 0; i <= up; i++)
{
int t = i<<(pos-1);
if(sum - t >= 0)
ans += dfs(pos-1, sum-t, flag||i<up);
}
if(flag)
dp[pos][sum] = ans;
return ans;
}
int solve(int x)
{
int pos = 0;
do
{
c[++pos] = x%10;
x /= 10;
}while(x);
int fa = 0, cnt = 0;
do
{
fa += (a%10)<<cnt;
a /= 10;
cnt++;
}while(a);
return dfs(pos, fa, 0);
}
signed main()
{
int T;
cin >> 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;
}