又重新学习了一遍数位dp,真的不太熟练
一个是对这个记忆化不太理解
后来看到就是说 假如现在搜3xxx,之前1xxx往后搜的时候3xxx已经搜过了,所以直接可以返回
dp[i][j]表示搜索到第i位总和不超过j的个数
所以最后求的就是dp[pos(b)][f(a)]
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <map>
#include <sstream>
#define LL long long
#define INF 0x3f3f3f3f
#define mod 1000000007
const int maxn = 300000+5;
using namespace std;
int dp[20][10000];//当前枚举到第i位,权值不超过j的个数
int ans;
int arr[maxn];
int dfs(int pos, int sum, bool limit){
if(pos == -1) return sum <= ans;
if(sum > ans) return 0;
if(!limit && dp[pos][ans-sum] != -1) return dp[pos][ans-sum];//记忆化搜索
int up = limit ? arr[pos] : 9;
int tot = 0;
for(int i=0; i<=up; i++){
tot += dfs(pos-1,sum+i*(1<<pos),limit && i==arr[pos]);
}
if(!limit) dp[pos][ans-sum] = tot;
return tot;
}
int solve(int a, int b){
int pos = 0;
while(b){
arr[pos++] = b % 10;
b /= 10;
}
ans = 0;
int i = 0;
while(a){
ans += (a%10)*(1<<i);
i++;
a /= 10;
}
return dfs(pos-1,0,true);
}
int main(){
int T, kases = 1;
scanf("%d",&T);
memset(dp, -1, sizeof(dp));
while(T--){
int a,b;
scanf("%d%d",&a,&b);
printf("Case #%d: %d\n",kases++,solve(a,b));
}
}