您的位置:首页 > 其它

POJ Round Numbers(数位DP)

2015-04-25 09:13 417 查看
题目大意:

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

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: