1. 程式人生 > >BZOJ_1662_[Usaco2006 Nov]Round Numbers 圓環數_數位DP

BZOJ_1662_[Usaco2006 Nov]Round Numbers 圓環數_數位DP

art sca 二進制 string CP 代碼 指定 clu 枚舉

BZOJ_1662_[Usaco2006 Nov]Round Numbers 圓環數_數位DP

Description

正如你所知,奶牛們沒有手指以至於不能玩“石頭剪刀布”來任意地決定例如誰先擠奶的順序。她們甚至也不能通過仍硬幣的方式。 所以她們通過"round number"競賽的方式。第一頭牛選取一個整數,小於20億。第二頭牛也這樣選取一個整數。如果這兩個數都是 "round numbers",那麽第一頭牛獲勝,否則第二頭牛獲勝。 如果一個正整數N的二進制表示中,0的個數大於或等於1的個數,那麽N就被稱為 "round number" 。例如,整數9,二進制表示是1001,1001 有兩個‘0‘和兩個‘1‘; 因此,9是一個round number。26 的二進制表示是 11010 ; 由於它有2個‘0‘和 3個‘1‘,所以它不是round number。 很明顯,奶牛們會花費很大精力去轉換進制,從而確定誰是勝者。 Bessie 想要作弊,而且認為只要她能夠知道在一個指定區間範圍內的"round numbers"個數。 幫助她寫一個程序,能夠告訴她在一個閉區間中有多少Hround numbers。區間是 [start, finish],包含這兩個數。 (1 <= Start < Finish <= 2,000,000,000)

Input

* Line 1: 兩個用空格分開的整數,分別表示Start 和 Finish。

Output

* Line 1: Start..Finish範圍內round numbers的個數

Sample Input

2 12

Sample Output

6


設f[i][j]為i位數中有j個1的方案數,然後發現這就是組合數。

枚舉每一位都可能是什麽,如果是1就算出這位是0時的方案。

需要記錄下前綴1的個數,這樣。

代碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int f[35][35],g[35],a[35],tot;
void init() {
    int i,j,k;
    for(i=0;i<=32;i++) f[i][0]=f[i][i]=1;
    for(i=1;i<=32;i++) {
        for(j=1;j<=i;j++) {
            f[i][j]=f[i-1][j-1]+f[i-1][j];
        }
    }
}
void build(int x) {
    if(!x) return ;
    a[++tot]=x%2;
    build(x/2);
}
int calc(int x) {
    if(!x) return 1;
    tot=0; build(x);
    int i,j,re=0,tmp=1;
    for(i=1;i<=tot-2;i++) {
        for(j=0;j-(i-j)+tmp<=0;j++) {
            re+=f[i][i-j];
        }
    }
    for(j=tot-1;j;j--) {
        if(a[j]==1) {
            tmp--;
            for(i=0;j-1-i>=0&&i-(j-1-i)+tmp<=0;i++) re+=f[j-1][j-1-i];
            tmp+=2;
        }
        else tmp--;
    }
    if(tmp<=0) re++;
    return re+1;
}
int main() {
    init();
    int l,r;
    scanf("%d%d",&l,&r);
    printf("%d\n",calc(r)-calc(l-1));
}

BZOJ_1662_[Usaco2006 Nov]Round Numbers 圓環數_數位DP