【POJ 3252】 Round Numbers 數位dp

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

題意:給個區間,輸出對應範圍內十進制的二進表達中0的數量大於等於1的數量的數的個數

思路(數位dp):

·和普通數位dp同樣的做法,十進制的數位表達同樣適用於二進制,只是把上限最大改爲了1,最小仍是0,依照題意,我們可以設置狀態數sta,比如初始化爲0,然後遇到0就對狀態數貢獻+1,否則(爲1)就對其-1,如果最後狀態數sta>=0就說明0的個數大於等於1的個數。
·所以可以用dp[pos][sta]表示在pos位置往時,狀態數等於sta時滿足題意的數的個數。因爲sta不能爲負,所以可以設初始值爲一個較大的常數,然後對比最後的sta>=add是否成立即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <algorithm>
#define maxn 10000+500
using namespace std;
typedef long long ll;
ll dp[60][150];         //dp[pos][sta] 代表pos位置往後滿足狀態量大於等於sta的數的個數
ll a[60];
ll add=50;
ll dfs(int pos, int sta,bool lead, bool limit)      //sta表示狀態增量,初始爲add
{
    if(pos==-1) return sta >= add;      //如果當前狀態不滿足 sta>=add返回0,滿足則返回貢獻度1
    if(!lead&&!limit&&dp[pos][sta]!=-1) return dp[pos][sta];        //記憶化搜索
    ll up = limit?a[pos]:1;         //01串, 前面有限制條件則當前位上限爲自身, 如 110 在前兩位固定是1的情況下第三位只能是0不能是1
    ll ans = 0;         
    for(ll i=0;i<=up;i++)
    {
        if(i==0&&lead)  ans += dfs(pos-1,sta, true, limit&&a[pos]==i );     //有前導零且當前爲也作前導零,不計入sta,繼續往下
       else  ans += dfs(pos-1,sta+(i==1?-1:1), false, limit&&a[pos]==i);        //否則就是正常二進制序列, 0 對狀態貢獻1, 1則貢獻-1,最後對比增量改變量和add就知道01數量對比
    }
    if(!limit&&!lead) dp[pos][sta] = ans;       //沒有限制條件就記憶化
    return ans;
}

ll solve(ll x)
{
    int pos=0;
    while(x)
    {
        a[pos++]=x&1;
        x>>=1;
    }
    return dfs(pos-1,add,true,true);
}
int main()
{
    memset(dp,-1,sizeof dp);
    ll a,b;
    while(~scanf("%lld%lld",&a,&b))
    {
        printf("%lld\n",solve(b)-solve(a-1));
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章