# 【hdu4734】【F(x)】数位dp + 小小的总结一下

(https://www.pixiv.net/member_illust.php?mode=medium&illust_id=65608478)

## Problem Description

For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).

## Input

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)

## Output

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.

3
0 100
1 10
5 100

## Sample Output

Case #1: 1
Case #2: 2
Case #3: 13

（终于找到时间写数位dp了。。）

f[pos][...]，dfs(pos,...,limit,[zero])

f[pos][sum]

（但是思路还是很巧妙的，所以要总结一下）

 1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5
6 int f[11][10000],a,b,len,orz[11],sum,mi[11];
7
8 int dfs(int pos,int pre,bool limit){
9     if(pos==0){
10         if(pre<=sum) return 1;
11         return 0;
12     }
13     if((!limit)&&f[pos][sum-pre]!=-1) return f[pos][sum-pre];
14     int st=limit?orz[pos]:9;
15     int ans=0;
16     for(int i=0;i<=st;i++)
17         if(pre+i*mi[pos]<=sum) ans+=dfs(pos-1,pre+i*mi[pos],limit&&i==st);
18     if(!limit) f[pos][sum-pre]=ans;
19     return ans;
20 }
21 int main(){
22     memset(f,-1,sizeof(f));
23     mi[1]=1;
24     for(int i=2;i<=10;i++) mi[i]=mi[i-1]*2;
25     int t;
26     scanf("%d",&t);
27     for(int k=1;k<=t;k++){
28         scanf("%d%d",&a,&b);
29         sum=0;
30         for(int i=a,j=1;i;i/=10,j++) sum+=mi[j]*(i%10);//printf("sum=%d\n",sum);
31         for(len=0,b;b;b/=10) orz[++len]=b%10;
32         printf("Case #%d: %d\n",k,dfs(len,0,1));
33     }
34     return 0;
35 } 
View Code

posted @ 2017-11-03 21:19  LinnBlanc  阅读(95)  评论(0编辑  收藏