POJ3252数位DP

题目大意:

给两个数字,然后用二进制来表示,求出当中的0大于等于1的个数的数字有几个

思路:

因为之前做了按位与的最大生成树,所以bit这里的就和那个差不多。然后就是用pre和status来分别表示1和0的个数了。但是这里我们要注意,最高位的1是否有放下(TAT这里我想到的,然而没有放到dfs函数中去)。其他的就是枚举就好了



#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int n, m, cnt; int bit[35]; int dp[35][35][35]; //知道最高位,剩下的枚举一下就可以了 //pos表示二进制的位数,pre表示1的个数,status表示二进制中0有几个 //first表示第一位是否使用,因为第一位如果没有使用,那么后来就会枚举出0,00,000,0000这样的序列 int dfs(int pos, int pre, int status, int flag, int first){ if (pos <= 0) return pre <= status; if (!first && !flag && dp[pos][pre][status] != -1) return dp[pos][pre][status]; ll res = 0; ll last = flag ? bit[pos] : 1; for (int i = 0; i <= last; i++){ int tmp1 = pre, tmp2 = status; if (first){ if (i == 0) res += dfs(pos - 1, tmp1, tmp2, flag && i == last, 1); else res += dfs(pos - 1, ++tmp1, tmp2, flag && i == last, 0); } else { if (i == 0) tmp2++; else if (i == 1) tmp1++; res += dfs(pos - 1, tmp1, tmp2, flag && i == last, 0); } } if (!first && !flag) dp[pos][pre][status] = res; return res; } int cal(int x){ cnt = 0; memset(bit, 0, sizeof(bit)); int n = x; while (n > 0){ ++cnt; n >>= 1; } int sum = cnt; int tmp = 0; while (sum){ ll res = (1 << (sum - 1));//1已经表明了是一位了 tmp += res; if ((tmp & x) == tmp){ bit[sum] = 1; } else { tmp -= res; bit[sum] = 0; } sum--; } /*for (int i = cnt; i >= 1; i--){ printf("%d", bit[i]); } printf("\n");*/ // printf("cnt = %d", cnt); return dfs(cnt, 0, 0, 1, 1); } int main(){ memset(dp, -1, sizeof(dp)); while (scanf("%d%d", &n, &m) == 2){ printf("%d\n", cal(m) - cal(n - 1)); } return 0; } </algorithm></cstring></cstdio>

你可能感兴趣的:(POJ3252数位DP)