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;
}

 

posted @ 2018-09-21 22:29  hinata_hajime  阅读(147)  评论(0编辑  收藏  举报