poj 3252 Round Numbers(二进制数位DP)

来源:互联网 发布:端口嗅探 编辑:程序博客网 时间:2024/06/06 02:44



Round Numbers
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 12505 Accepted: 4790

Description

The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, Paper, Stone' (also known as 'Rock, Paper, Scissors', 'Ro, Sham, Bo', and a host of other names) in order to make arbitrary decisions such as who gets to be milked first. They can't even flip a coin because it's so hard to toss using hooves.

They have thus resorted to "round number" matching. The first cow picks an integer less than two billion. The second cow does the same. If the numbers are both "round numbers", the first cow wins,
otherwise the second cow wins.

A positive integer N is said to be a "round number" if the binary representation of N has as many or more zeroes than it has ones. For example, the integer 9, when written in binary form, is 1001. 1001 has two zeroes and two ones; thus, 9 is a round number. The integer 26 is 11010 in binary; since it has two zeroes and three ones, it is not a round number.

Obviously, it takes cows a while to convert numbers to binary, so the winner takes a while to determine. Bessie wants to cheat and thinks she can do that if she knows how many "round numbers" are in a given range.

Help her by writing a program that tells how many round numbers appear in the inclusive range given by the input (1 ≤ Start < Finish ≤ 2,000,000,000).

Input

Line 1: Two space-separated integers, respectively Start and Finish.

Output

Line 1: A single integer that is the count of round numbers in the inclusive range Start..Finish

Sample Input

2 12

Sample Output

6

Source

USACO 2006 November Silver

<span style="color: rgb(204, 0, 0);"><span style="font-size:32px;">题意:算出区间内每个数二进制中0的个数大于等于1的个数的数字有多少个</span></span>
思路:把n换成二进制,对这个2进制进行操作,比如16的二进制是10000,一共5位,这样他后面的4位随意怎么变都会比16小,所以枚举这一个01串就是所有的答案。。。数位注意的是 因为是2进制,所以要有一个数字,必须从第一位是1开始算。。。比如16 是 10000, 枚举到00110,这样会是0比1多,但是这个数实际应该是110.。。。一开始卡在这里。。。其余的就是一般的dp了,用dp[][][]分别记录len,0的数量,1的数量。其实dp数组根dfs传的变量是一样的。。。

注意统计某个数里面某些数字的个数,在dfs时候注意下个数组要清零。。

代码:

<span style="font-size:24px;">#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int maxn = 1e2;int dp[maxn][maxn][maxn], bit[maxn]; //分别表示长度,0的个数,1的个数int dfs(int len, int zero, int one, int lead, int limit)  //lead表示是否出现过1{    if(len < 1) return lead && zero >= one;  //如果出现过1并且0比1多就返回1 加lead是为了预防0    if(!limit && dp[len][zero][one] != -1) return dp[len][zero][one];    int ans = 0;    int last = limit ? bit[len] : 1;    for(int i = 0; i <= last; i++)    {        if(i) ans += dfs(len-1, zero, one+1, 1, limit && i == last); //如果是1那就无所谓了        if(!i && lead) ans += dfs(len-1, zero+1, one, 1, limit && i == last);//0+之前出现过1        if(!i && !lead) ans += dfs(len-1, 0, 0, 0, limit && i == last);//这里不加就错了    } //不是像其他的如果不需要直接continue;这里要重置zero跟one的个数;<span style="white-space:pre"></span>其余的题都是在dfs开始    if(!limit) dp[len][zero][one] = ans;//ans = 0重置了,这里一个数结束后,通过这个语句重置    return ans;<span style="white-space:pre"></span>//否则会0,1会一直递增的}int cal(int n){    int k = 0;    while(n)    {        bit[++k] = n % 2;        n /= 2;    }    memset(dp, -1, sizeof(dp));    return dfs(k, 0, 0, 0, 1); //一开始是0}int main(){    int n, m;    while(~scanf("%d%d", &n, &m))    {        printf("%d\n", cal(m) - cal(n-1));    }    return 0;}<span style="color:#ff0000;"></span></span>


2 0