• HDU


    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
    ",Case,solve(r));
        }
        return 0;
    }
  • 相关阅读:
    2019沈阳网路赛 D. Fish eating fruit (点分治)
    2019南京网路赛 A.The beautiful values of the palace (主席树)
    洛谷 P2634 [国家集训队]聪聪可可(点分治)
    AcWing252 树 (点分治模板题)
    点分治模板 (洛谷 P3806)
    2020牛客寒假算法基础集训营2 J-求函数(线段树维护矩阵乘法)
    七夕祭(贪心+中位数)
    数据结构-集合
    数据结构-广义表
    数据结构-稀疏矩阵
  • 原文地址:https://www.cnblogs.com/a249189046/p/9688797.html
Copyright © 2020-2023  润新知