POJ 3252 Round Numbers(數位DP)

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


題意:一個十進制數化成2進制,要是二進制數裏0的個數不小於1的個數稱爲圓數,現在給出一個區間(n,m),問裏面有多少圓數。

解題思路:將數轉換爲二進制數後,直接比較當前0的數量是否不小於1的數量,dp[pos][sum]表示在pos位上0的數量減去1的數量不少於num的方案數,需要提前將sum賦一個初值,而且本題是計算二進制中0,1的個數,所有在記憶化的時候需要考慮前導0的影響。代碼註釋較多,容易懂。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int dp[50][100];//2e9大概30多位,直接開50.
int a[50];
int dfs(int pos,int sum,int lead,int limit){
    if(pos==-1)
        return sum>=50;//判斷0的個數是否大於1的個數
    if(!limit&&!lead&&dp[pos][sum]!=-1)//要統計0的數量,前導零是有影響的
        return dp[pos][sum];
    int up=limit?a[pos]:1;//二進制位上最大位1.
    int tmp=0;
    for(int i=0;i<=up;i++){
        if(i==0){
            if(lead)//前一位爲0,當前位爲1,sum的值不變
                tmp+=dfs(pos-1,sum,1,limit&&i==a[pos]);
            else
                tmp+=dfs(pos-1,sum+1,0,limit&&i==a[pos]);//當前位爲0,sum+1.
        }
        else
            tmp+=dfs(pos-1,sum-1,0,limit&&i==a[pos]);//當前位爲1,sum-1.
    }
    if(!limit&&!lead)//跟上面的記憶化一樣需要考慮前導0的影響
        dp[pos][sum]=tmp;
    return tmp;
}
int solve(int n)
{
    int len=0;
    while(n)
    {
        a[len++]=n&1;
        n>>=1;
    }
    return dfs(len-1,50,1,1);//處理成2進制數,把sum賦一個初值,
    //中間某個pos位上sum可能爲負數(這不一定是非法的,因爲我還沒枚舉完嘛,只要最終的sum>=0才能判合法,中途某個pos就不一定了)
}
int main()
{
    int n,m;
    memset(dp,-1,sizeof dp);//多組輸入,初始化放外面,會快一點
    while(~scanf("%d%d",&n,&m)){
        printf("%d\n",solve(m)-solve(n-1));
    }
    return 0;
}

發佈了43 篇原創文章 · 獲贊 26 · 訪問量 3988
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章