HDU 4734 - F(x) (数位DP)
题目链接 https://cn.vjudge.net/problem/HDU-4734
【题目描述】
For a decimal number with digits we define its weight as . Now you are given two numbers and , please calculate how many numbers are there between and , inclusive, whose weight is no more than .
The first line has a number T (T <= 10000) , indicating the number of test cases.
For each test case, there are two numbers A and B (0 <= A,B < 109)
For every case,you should output “Case #t: ” at first, without quotes. The t is the case number starting from 1. Then output the answer.
【思路】
数位DP,设 表示当前处于pos位时,还有sum的权值可以减掉对应的数字个数,根据来计算,边界是当时,如果 则有一个合法数字,否则没有,当 时肯定无解,及时停止搜素
#include<bits/stdc++.h>
using namespace std;
int all;
int a[20];
int dp[20][6000];
int F(int x){
int ans=0;
int pw=0;
while(x){
ans+=(x%10)*(1<<pw);
x/=10;
++pw;
}
return ans;
}
int dfs(int pos,int sum,bool limit){
if(-1==pos) return sum>=0 ? 1 : 0;
if(sum<0) return 0;
if(!limit && dp[pos][sum]!=-1) return dp[pos][sum];
int up=limit? a[pos] : 9;
int ans=0;
for(int i=0;i<=up;++i){
ans+=dfs(pos-1,sum-i*(1<<pos),limit && i==up);
}
if(!limit) dp[pos][sum]=ans;
return ans;
}
int solve(int x){
int pos=0;
while(x){
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,all,true);
}
int main(){
int T;
scanf("%d",&T);
memset(dp,-1,sizeof(dp));
for(int kase=1;kase<=T;++kase){
int A,B;
scanf("%d%d",&A,&B);
all=F(A);
printf("Case #%d: %d\n",kase,solve(B));
}
return 0;
}