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 */