HDU - 4734 F(x) (数位DP)

For a decimal number x with n digits (A nA n-1A n-2 ... A 2A 1), 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).

InputThe 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)OutputFor 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

分析:该题目数据的组数很多,且数的范围很大,能够想到使用数位DP来解决,但是需要注意DP的第二维应该用什么,容易想到的是,使用前面为止各个数位按照公式得到的值的总和,然后最后再比较这个值和F(A)     但是需要这样的话,会由于数据的组数过多,而我们每次需要重置DP数组,而超时,因为每组数据,DP的值只能单独使用(A的值不同导致的)     但是换一种角度的话,如果我们使用F(A)和当前值的差的话,这样DP就具有了对于所有的数据的泛用性,因为我们只需要考虑它减去剩下的数位得到的值,是否大于等于0

代码如下:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
LL a[20];
LL dp[12][5050];
LL two[20];
LL cmp;
   LL x,r,t,f,Case=0,ini;
LL dfs(int num,LL now,bool limit)   //位数,传递条件 ,上界判断
{
    if(num==-1)
    return 1;
    //最后一位时,根据情况返回1或0
    if(!limit && dp[num][now]!=-1)      //已经走过此种状态
        return dp[num][now];
    LL ans=0;      //计数
    int up=limit?a[num]:9;    //上界
    for(int i=0;i<=up;i++){
        if(i*two[num]>now)break;
        ans+=dfs(num-1,now-i*two[num],limit && i== up);//传递
    }
    if(!limit)  //判断是否可以储存
        dp[num][now]=ans;
    return ans;
}

LL solve(LL x)    //将x拆开存入a数组
{
    int num=0;
    while(x){
        a[num]=x%10; //b表示进制!!!
        num++;
        x/=10;
    }
 /*  for(int i=0;i<=num-1;i++)
        for(int j=0;j<=cmp;j++)
         dp[i][j]=-1;*/
    return dfs(num-1,cmp,true);//传递
}

int main()
{
    two[0]=1;
    for(int i=1;i<=15;i++)
    two[i]=two[i-1]*2;
    memset(dp,-1,sizeof(dp));
    scanf("%lld",&t);
    while(t--)
    {
        ini=0;

        f=1;
        cmp=0;
        Case++;
        scanf("%lld%lld",&x,&r);
        LL tmp=r;
        while(x>0)
        {
          cmp+=(x%10)*f;
          f*=2;
          x/=10;
        }
       printf("Case #%lld: %lld\n",Case,solve(r));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/a249189046/p/9688797.html

时间: 2024-10-20 01:01:56

HDU - 4734 F(x) (数位DP)的相关文章

HDU 4734 F(x)(数位DP)

Description For a decimal number x with n digits (A nA n-1A n-2 ... A 2A 1), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there betwe

HDU ACM 4734 F(x)-&gt;数位DP入门练习题

分析:数位DP的入门联系题,通过该題对数位DP有感觉了:dp[len][presum]代表长度为len权值不大于presum的数.记忆化搜索提高效率,除边界(因为边界上算出来的答案在其它数中可能是不完整的)外记录dp[len][presum]的值,下次发现以前计算过就直接return:dfs(len, presum, fg)表示求长度为len,不超过pre的全部符合条件的值.fg是控制边界的. #include<iostream> using namespace std; int dp[11]

HDU - 4734 F(x) (2013成都网络赛,数位DP)

题意:求0-B的满足<=F[A]的所有可能 思路:数位DP,记忆化搜索 #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; int A, B; int dp[20][200000]; int bit[20]; int dfs(int cur, int num, int flag) { if (cur == -

HDU 4734 F(x)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 题意:对于一个n位的十进制数字x=(AnAn-1An-2 ... A2A1),定义 F(x)=An*2n-1+An-1*2n-2+ ...+A2*2+A1*1.给出A.B,求在[0,B]之间有多少数字满足F(x)<=F(A)? 思路:数位DP.f[dep][x]表示到达dep剩余为x的方案数. i64 n,m; i64 f[25][N]; int a[25],num; i64 Sum; i64

HDU 2089 不要62(数位DP,三种姿势)

HDU 2089 不要62(数位DP,三种姿势) ACM 题目地址:HDU 2089 题意: 中文题意,不解释. 分析: 100w的数据,暴力打表能过 先初始化dp数组,表示前i位的三种情况,再进行推算 直接dfs,一遍搜一变记录,可能有不饥渴的全部算和饥渴的部分算情况,记录只能记录全部算(推荐看∑大的详细题解Orz) 代码: 1. 暴力 (以前写的) /* * Author: illuz <iilluzen[at]gmail.com> * File: 2089_bf.cpp * Create

HDU 4518 ac自动机+数位dp

吉哥系列故事--最终数 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 304    Accepted Submission(s): 102 Problem Description 在2012年腾讯编程马拉松比赛中,吉哥解决了一道关于斐波那契的题目,这让他非常高兴,也更加燃起了它对数学特别是斐波那契数的热爱.现在,它又在思考一个关于斐波那契

HDU 4734——F(x)

HDU 4734——F(x) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4734 题意:数i在0~B的范围内,求F(i)小于F(A)的个数 F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1 先把F(A)算出来=tot,然后按位计算,如果num(当前F(pos)<=tot,方案数+1 返回1,如果num>tot,返回0) dp[pos][num] 的状态表示为dp[当前第几位][最大值t

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就