标签:style blog http color io ar for div log
http://poj.org/problem?id=3252
题意:问从a到b有多少个round number。如果某数的二进制表示中0的个数不少于1的个数,那么它就是一个round number。
分析:数位dp。就我目前碰到的几道数位dp来说,其实所谓数位dp,就是和组合数有联系的递推罢了。还是转换为从0到a,我们先考虑二进制下长度小于a的数,即随便填0和1,那么就是用组合数算一下就可以了。然后考虑长度相等的,我们从高位往下走,已经枚举的就默认是a对应位的数。如果当前位是0,我们累计0的个数然后继续,如果是1,那么就可以变成0来考虑,之后的数又可以随便填,也是组合数算一下。这里会漏掉0和这个数本身,再单独算一下就行。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 int a, b; 6 int c[40][40]; 7 int d[40]; 8 void init() 9 { 10 for (int i = 0; i <= 32; i++){ 11 c[i][0] = 1; 12 for (int j = 1; j <= i; j++) 13 c[i][j] = c[i][j-1] * (i-j+1) / j; 14 } 15 } 16 int cal(int x) 17 { 18 if (x == -1) return 0; 19 int ret = 1, len = 0; //初始值为1,即0这个数 20 while(x){ 21 d[len++] = x & 1; 22 x >>= 1; 23 } 24 for (int i = 1; i < len; i++) //长度为i(小于x的长度) 25 for (int j = 0; j+1 <= i/2; j++) //第一位为1,枚举之后有j个1 26 ret += c[i-1][j]; 27 int zero = 0, one = 1; 28 for (int i = len-2; i >= 0; i--){ 29 if (d[i]){ 30 zero++; 31 for (int j = 0; j <= i && j+one <= zero+(i-j); j++) 32 ret += c[i][j]; 33 zero--; 34 one++; 35 } 36 else zero ++; 37 } 38 if (zero >= one) ret++; //单独算x本身 39 return ret; 40 } 41 int main() 42 { 43 init(); 44 while(scanf("%d %d", &a, &b) != EOF) 45 { 46 printf("%d\n", cal(b) - cal(a-1)); 47 } 48 return 0; 49 }
标签:style blog http color io ar for div log
原文地址:http://www.cnblogs.com/james47/p/3942259.html