F(x)
Time Limit: 1000/500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7839 Accepted Submission(s): 3080
Problem Description
For a decimal number x with n digits (A
nA
n-1A
n-2 ... A
2A
1), we define its weight as F(x) = A
n * 2
n-1 + A
n-1 * 2
n-2 + ... + A
2 * 2 + A
1 * 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 < 10 9)
For each test case, there are two numbers A and B (0 <= A,B < 10 9)
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
30 1001 105 100
Sample Output
Case #1: 1Case #2: 2Case #3: 13
Source
/**
题意:定义f(x) 给定A B两个数 求解使得f(i)<=f(A) i---[0,B];i的个数
基础数位DP 直接计算f(A) 对B进行数位DP 统计B中存在多少大于等于f(A);
dp[len][digit]:表示当前位为len下f(A)值为digit下的满足大于原始f(A)的值的个数;
*/
#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int maxn=20+7;
int dp[maxn][4600],num[maxn];
int fac[maxn];
int dfs(int len,int digit,bool end_flag){
if(digit<0) return 0;
if(len==-1) return digit>=0;
if(!end_flag&&dp[len][digit]!=-1) return dp[len][digit];
int maxx=end_flag?num[len]:9;
int ans=0;
for(int i=0;i<=maxx;i++)
ans+=dfs(len-1,digit-fac[len]*i,i==maxx&&end_flag);
if(!end_flag) dp[len][digit]=ans;
return ans;
}
int f(int n){
int ans=1;
int sum=0;
while(n){
sum+=n%10*ans;
ans*=2;
n/=10;
}
return sum;
}
int solved(int A,int B){
int len=0;
while(B){
num[len++]=B%10;
B/=10;
}
return dfs(len-1,f(A),true);
}
int main (){
fac[0]=1;
for(int i=1;i<=20;i++) fac[i]=fac[i-1]*2;
int t;
cin>>t;
memset(dp,-1,sizeof(dp));
for(int cas=1;cas<=t;cas++){
memset(num,0,sizeof(num));
int A,B;
scanf("%d %d",&A,&B);
printf("Case #%d: %d\n",cas,solved(A,B));
}
return 0;
}