HDU 4734 —— F(x)

Time Limit:500MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
 

Description

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
 
这题很关键的一点是要懂得,将终点统一为>=0
回顾很多的“数位DP”问题,它们的终点都是一致的!
 
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
using namespace std;

int b[10], num[10];
int dp[10][9*((1<<10)-1)];

int dfs(int u, int f, bool limit)
{
    if(u < 1)    return 1;
    if(!limit && dp[u][f] != -1)    return dp[u][f];
    
    int maxn = limit ? b[u] : 9;
    int ret = 0, cur;
    
    for(int i=0; i<=maxn; i++) {
        cur = f - i*(1<<u-1);
        if(cur > 0) {
            ret += dfs(u-1, cur, limit && i==maxn);
        } else if(cur == 0) {
            ret += 1;
        }
    }
    
    if(!limit)    dp[u][f] = ret;
    return ret;
}

int f(int n, int a)
{
    int lenb=0;
    memset(b, 0, sizeof(b));
    while(n) {
        b[++lenb] = n%10;
        n /= 10;
    }
    return dfs(lenb, a, 1);
}

int main ()
{
    num[0] = 1;
    for(int i=1; i<10; i++) {
        num[i] = num[i-1] * 10;
    }
    
    int T, A, B;
    scanf("%d", &T);
    memset(dp, -1, sizeof(dp));
    for(int kase=1; kase<=T; kase++) {
        scanf("%d%d", &A, &B);
        int base = 1, F=0;
        while(A) {
            F += base * (A % 10);
            
            base <<= 1;
            A /= 10;
        }
        printf("Case #%d: %d\n", kase, f(B, F));
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/AcIsFun/p/5389187.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值