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\n", solve(a));
    //    printf("%I64d\n", solve(b));
        printf("%I64d\n", 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

*/
时间: 2024-08-24 17:09:03

POJ Round Numbers(数位DP)的相关文章

POJ 3252 Round Numbers(数位dp&amp;amp;记忆化搜索)

题目链接:[kuangbin带你飞]专题十五 数位DP E - Round Numbers 题意 给定区间.求转化为二进制后当中0比1多或相等的数字的个数. 思路 将数字转化为二进制进行数位dp,由于一个二进制数的最高位必须为1.所以设置变量first记录前面位是否有1,若有1,则可随意放,否则,仅仅可放1. 同一时候.上面的推断决定了搜索时len的大小与二进制本身的长度不一定相等,所以需两个变量对1和0的个数进行记录. 用dp[a][b][c]保存长度a,b个0,c个1的数字个数.记忆化搜索.

POJ 3252 Round Numbers (数位DP)

题意:求区间内一个数二进制位1的数量大于等于0的数的个数. 析:dp[i][j][k] 表示前 i 位,长度为 j 的,1的数量是 k.注意前导0. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <

POJ 3252 round numbers(数位DP)

#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <vector> #include <queue> #include <cstring> #include <set> #include <stack> #include <m

POJ 3252 Round Numbers 数位dp(入门

题目链接:点击打开链接 题意: 给定一个区间,求区间内有多少个合法数(当这个数的二进制中0的个数>=1的个数称为合法数 二进制无前导0) 思路: cnt[i]表示二进制长度为i位(即最高位为1,其他位任意)时的合法数个数. sum[i] 就是二进制长度<=i位的合法数个数. 然后从最高位枚举到低位即可.维护当前0的个数. #include <cstdio> #include <algorithm> #include <cstring> #include &l

poj 3340 Barbara Bennett&#39;s Wild Numbers(数位DP)

Barbara Bennett's Wild Numbers Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3153   Accepted: 1143 Description A wild number is a string containing digits and question marks (like 36?1?8). A number X matches a wild number W if they hav

cf55dBeautiful numbers数位dp

想到 最小公倍数 其余的就好搞了 ,可是没想到 #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <

Balanced Numbers数位dp

三进制搞下, 0  表示没出现过,  第i位为1 表示 i出现了奇数次,  2表示i 出现了偶数次. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #includ

[Codefoces 401D]Roman and Numbers 数位dp

http://codeforces.com/problemset/problem/401/D 题目大意:给定一个数字n,将n的每一位数字重新排列,求在这些排列数之中可以被n整除的方法数. 解题思路: 暴力超时-- 大多数人的写法是进行位压缩,不过那样的话需要2^18*100 的空间,效率比较低,重复状态数较多,处理起来也不方便,这一题是给出了512M的空间.但是如果空间再小一倍,前者的方法就无能为力了. 发现有一种对于数位dp来说比较好的状态压缩方式,直接根据数码x出现的次数进行状态压缩.比如说

uva 10712 - Count the Numbers(数位dp)

题目链接:uva 10712 - Count the Numbers 题目大意:给出n,a,b:问说在a到b之间有多少个n. 解题思路:数位dp,dp[i][j][x][y]表示第i位为j的时候,x是否前面是相等的,y是否已经出现过n.对于n=0的情况要特殊处理前导0,写的非常乱,搓死. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using na