求出在([1, b])里有多少个数字的(F(i) leq F(a))
首先算出(F(a))的值,然后套一下数位dp板子即可
同时记录其权值变化,对于每一个base就是(2^{pos})
但是选择记录当前权值然后最后比较是否小于等于(F(a))是不行的
因为记忆化搜索就会记录有多少个权值是小于第一个(F(a)),所以需要改变一下。
设初始值为(F(a)),然后去减每位的权值,最后判断权值是否大于等于0即可。
记住,记忆化搜索的话,就必须保持记录的值是同一条件的
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int dp[10][4600];
int a[20];
int base[30];
int maxx = 0;
int dfs(int pos, bool limit, int now){
if(pos == -1) return now >= 0;
if(now < 0) return 0;
if(!limit && now >= 0 && dp[pos][now] != -1) return dp[pos][now];
int up = limit ? a[pos] : 9;
int tmp = 0;
for(int i = 0; i <= up; i++) {
tmp += dfs(pos - 1, limit && i == up, now - i * base[pos]);
}
if(!limit && now >= 0) dp[pos][now] = tmp;
return tmp;
}
int solve(int n){
int pos = 0;
while(n){
a[pos++] = n % 10;
n /= 10;
}
return dfs(pos - 1, 1, maxx);
}
void init(int n){
int base = 1;
while(n){
maxx += n % 10 * base;
n /= 10;
base *= 2;
}
}
int main(){
for(int i = 0; i <= 30; i++) base[i] = 1 << i;
int t;
memset(dp, -1, sizeof(dp));
scanf("%d", &t);
for(int i = 1; i <= t; i++) {
maxx = 0;
int a, b;
scanf("%d%d", &a, &b);
init(a);
printf("Case #%d: %d
", i, solve(b));
}
return 0;
}