• POJ Round Numbers(数位DP)


    题目大意:

    Round Number:  将一个整数转化为二进制数字后,(不含前导0) 要是0的个数 大于等于1的个数 则是 Round Number

    问从L-R之中有多少个Round Number

    题目分析:

    要转化为2进制数字,我们用10进制保存明显不好判断0和1的个数,所以选择用8进制来存储,这样的话每一次进位会多出 ”000“, 然后再加上8进制的尾数, 最后我们可以得出增加了几个 1 和 增加了 几个 0

    需要注意的一点就是, 当前面的数字小于 8 的时候 我们要对 前导 0 进行特殊判断

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef __int64 LL;
    LL dp[20][163][133];//dp[位数][0的个数][1的个数]
    int bit[50];
    int binary[8][2] = { {3,0}, {2,1},{2,1},{1,2},{2,1},{1,2},{1,2},{0,3} };
    LL dfs(int pos,int preCou0,int preCou1,int flag,int len)
    {
        if(pos == -1)
        {
            return  (preCou1 || preCou0) && preCou0 >= preCou1;//这里要对 0 进行特殊判断, 将0去掉
        }
    
        if( !flag && dp[pos][preCou0][preCou1] != -1)
            return dp[pos][preCou0][preCou1];
    
        LL ans = 0;
        int end = flag?bit[pos]:7;
    
        for(int i=0; i<= end; i++)
        {
            int nowCou0 = preCou0 + binary[i][0];
            int nowCou1 = preCou1 + binary[i][1];
            if(preCou0 == 0 && preCou1 == 0)//判断是否是第一位,若是第一位则需要进行特殊处理
            {
                if(i == 0 || i == 1)nowCou0 = 0;
                if(i == 2)nowCou0 = 1;
                if(i == 3)nowCou0 = 0;
            }
    
            ans += dfs(pos-1, nowCou0, nowCou1, flag && i == end, len);
        }
        if(!flag)
            dp[pos][preCou0][preCou1] = ans;
    
        return ans;
    }
    
    
    LL solve(LL n)
    {
        int len = 0;
    
        while(n)
        {
            bit[len++] = n%8;
            n /= 8;
        }
        
        return dfs(len-1, 0, 0, 1, len-1);
    }
    
    int main()
    {
        LL a, b;
        
        memset(dp, -1 ,sizeof(dp));
        while(scanf("%I64d%I64d", &a, &b) != EOF)
        {
        //    printf("%I64d
    ", solve(a));
        //    printf("%I64d
    ", solve(b));
            printf("%I64d
    ", solve(b) - solve(a-1) );
        }
        return 0;
    }
    
    /*
    
    0的个数 大于等于 1的个数
    1    0001
    2    0010   1
    3    0011
    4    0100   1
    5    0101
    6    0110 
    7    0111
    8    1000   1
    9    1001   1
    10   1010   1
    11   1011
    12   1100   1
    13   1101   
    14   1110
    15   1111
    16   10000  1
    
    */
  • 相关阅读:
    VS2013快速安装教程
    软件工程课程的感想
    GitHub和Microsoft TFS对比有什么优势
    拼接素数
    C语言程序题
    vue中的实例方法的底层原理
    ios 安卓
    防抖
    伪数组转真数组的放法
    http和https的一种能力?
  • 原文地址:https://www.cnblogs.com/chenchengxun/p/4455377.html
Copyright © 2020-2023  润新知