数位DP
题意:
定义: F(x)=An∗2n−1+An−1∗2n−2+...+A2∗2+A1∗1 为一个数子x的权重,现在给出一个数字A,可以求出它的权重,问0~B之间有多少权重小于等于A的权重的数字。
思路:
考虑到A的范围,它的权重最大也不超过10000,所以可以定义:
dp[i][sum] 第i位数字里面所有满足权重小于等于sum 的个数。
那么按照简单数位DP就可以很容易写出来。
- 注意边界条件
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int A,B,bit[10];
int dp[10][10005];
int F(int x)
{
int ans = 0;
int len = 0;
while(x) {
ans += (x%10)*(1<<len);
len++;
x /= 10;
}
return ans;
}
int dfs(int pos,int sum,int e)
{
if(pos == -1) return sum >= 0;
if(sum < 0) return 0;
if(!e && dp[pos][sum] != -1) return dp[pos][sum];
int End = e ? bit[pos] : 9;
int ans = 0;
for(int i = 0;i <= End; i++) {
ans += dfs(pos-1,sum - i*(1<<pos),e && i == End);
}
if(!e) dp[pos][sum] = ans;
return ans;
}
int solve()
{
int pos = 0;
while(B) {
bit[pos++] = B%10;
B /= 10;
}
return dfs(pos-1,F(A),1);
}
int main()
{
//freopen("in.txt","r",stdin);
int tt,ncase = 1;
scanf("%d",&tt);
memset(dp,-1,sizeof(dp));
while(tt--) {
scanf("%d%d",&A,&B);
printf("Case #%d: %d\n",ncase++,solve());
}
return 0;
}