题目分析
数位dp基础题,状态挺容易想到的,因为数字只有10位,2^9还不到才512,即使每一位都是9,运用等比数列求和知不超过5000,因此dp数组第一位表示位数,第二位就表示计算出来的f函数值,那么我们每一次就找小于F(A)的即可,同样要满足B的限制,这样就可以顺利写出状态转移方程了
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 15;
int dp[maxn][5000], bit[maxn];
int A,B;
int F(int x){
int temp[maxn];
int len = 0;
while(x){
temp[len++] = x%10;
x /= 10;
}
int cnt = 1,sum = 0;
for(int i = 0; i < len; i++){
sum += temp[i]*cnt;
cnt *= 2;
}
return sum;
}
int dfs(int pos,int rest,int limit){
if(pos < 1) return rest >= 0;
if(rest < 0) return 0;
if(!limit && dp[pos][rest] != -1) return dp[pos][rest];
int ret = 0;
int len = limit?bit[pos]:9;
for(int i = 0; i <= len; i++)
ret += dfs(pos-1, rest-i*(int)pow(2.0,(pos-1)), limit&&i==len);
if(!limit) dp[pos][rest] = ret;
return ret;
}
int solve(int n){
int len = 0;
while(n){
bit[++len] = n%10;
n /= 10;
}
return dfs(len, F(A), 1);
}
int main(){
int T;
scanf("%d", &T);
memset(dp, -1, sizeof(dp));
for(int kase = 1; kase <= T; kase++){
scanf("%d%d", &A, &B);
printf("Case #%d: %d\n", kase, solve(B));
}
return 0;
}