Sweety

Practice makes perfect

导航

HDU 4734 F(x)(数位DP)

Posted on 2017-04-28 11:13  蓝空  阅读(194)  评论(0编辑  收藏  举报



For a decimal number x with n digits (A nn-1n-2 ... A 21), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 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 < 10 9)
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.
Sample Input
3
0 100
1 10
5 100
Sample Output
Case #1: 1
Case #2: 2
Case #3: 13
Hint




题意:

我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2)+...a(2)*2+a(1)*1,a(i)表示十进制数x中第i位的数字。

   题目给出a,b,求出有多少个F(i)(0<=i<=b)不大于f(a)的数。


基础的数位DP题目


#include <bits/stdc++.h>
using namespace std;

int dp[20][10000];  ///dp[i][j]是i位置之前的和小于sum的个数
int bit[20];

int dfs(int pos,int num,bool flag)
{
    if(pos == -1)return num >= 0; ///出口
    if(num < 0)return 0;           ///剪枝

    if(!flag && dp[pos][num] != -1)
        return dp[pos][num];

    int ans = 0;
    int end = flag?bit[pos]:9;
    for(int i = 0;i <= end;i++)
        ans += dfs(pos-1,num - i*(1<<pos),flag && i==end);


    if(!flag)  dp[pos][num] = ans;
    return ans;
}

int F(int x)
{
    int ret = 0;
    int len = 0;
    while(x)
    {
        ret += (x%10)*(1<<len);
        len++;
        x /= 10;
    }
    return ret;
}

int calc(int A,int B)
{
    int len = 0;
    while(B)
    {
        bit[len++] = B%10;
        B/=10;
    }
    return dfs(len-1,F(A),1);
}

int main()
{
    int T,A,B;
    int iCase = 0;
    scanf("%d",&T);
    memset(dp,-1,sizeof(dp));
    while(T--)
    {
        iCase++;
        scanf("%d%d",&A,&B);
        printf("Case #%d: %d\n",iCase,calc(A,B));
    }
    return 0;
}