BZOJ_1662_[Usaco2006 Nov]Round Numbers 圓環數_數位DP
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 12Sample 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