题意:
求出存在[0,B]中x使得F(x)小于等于F(A)的数有多少个。
题解:
首先求出F(A)的值,用这个值作为标记的初始值,第一维代表当前位置,第二维代表剩余值。而第二维的取值,最多能达到9*9*2^8,计算过程中,如果sum小于0,代表不可能因为要保证必须比F(A)小,直接返回0,而减的过程中,直接用i*(1<<pos) (pos为当前位置,i为当前取值),这题不需要理会前导零的问题。
状态转移的话,dp[i][j] 第一维表示当前位置,第二维表示剩余的值(即当前位置往后计算的过程中不能超过的值)。
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=2e4+1e3;//9*9*2^8
const int M=10;
int num[M];
int dp[M][N];
int dfs(int pos,int sum,bool limit)
{
if (pos==-1)
return sum>=0;
if (sum<0)
return 0;
if (!limit && dp[pos][sum]!=-1)
return dp[pos][sum];
int cnt=0;
int mx=limit?num[pos]:9;
for (int i=0 ; i<=mx ; ++i)
cnt+=dfs(pos-1,sum-i*(1<<pos),limit && i==num[pos]);
if (!limit)
dp[pos][sum]=cnt;
return cnt;
}
int f(int x)
{
int sum=0,two=1;
while (x)
{
sum+=(x%10)*two;
x/=10;
two*=2;
}
return sum;
}
int solve(int a,int b)
{
int pos=0;
while (b)
{
num[pos++]=b%10;
b/=10;
}
return dfs(pos-1,f(a),1);
}
int main()
{
int T;
scanf("%d",&T);
memset(dp,-1,sizeof(dp));
for (int test=1 ; test<=T ; ++test)
{
int a,b;
scanf("%d%d",&a,&b);
printf("Case #%d: %d\n",test,solve(a,b));
}
return 0;
}