1. 程式人生 > >poj 3252 Round Numbers(數學)

poj 3252 Round Numbers(數學)

div org 。。 cout false fin .org 第一個 num

鏈接:http://poj.org/problem?id=3252

題意:一個數寫成二進制,0不少於1就是round number,求給定區間內round number的個數。

分析:顯然第一步轉化為0到n的round number個數。。設n寫成二進制有len位,第一位取0時,後面只要滿足0的個數要求就行了,不用考慮是否比n大。。可以先預處理一下長度不大於len的round number個數,記做t[len],t[len]=t[len-1]+∑C(len-1 k) , (k=0,1,...,len/2-1)。

然後第一位取1時,往後是0的位只能取0,遇到第一個1時,再分情況考慮這一位為1和為0,然後考慮還需要多少位,往下遞歸即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=35;
 6 int C[maxn][maxn],sum[maxn][maxn][maxn],t[maxn];
 7 int start,finish;
 8 void CalC(){
 9     for(int i=1;i<maxn;i++)
10         C[i][0]=C[i][i]=1;
11     for(int i=2;i<maxn;i++){
12 for(int j=1;j<i;j++){ 13 C[i][j]=C[i-1][j]+C[i-1][j-1]; 14 } 15 } 16 for(int i=0;i<maxn;i++){ 17 for(int s=0;s<=i;s++){ 18 sum[i][s][s]=C[i][s]; 19 for(int t=s+1;t<=i;t++){ 20 sum[i][s][t]=sum[i][s][t-1]+C[i][t];
21 } 22 } 23 } 24 } 25 void CalT(){ 26 t[1]=1; 27 for(int i=2;i<maxn;i++){ 28 t[i]=t[i-1]+sum[i-1][0][(i-2)/2]; 29 } 30 } 31 int f(int n,int c,int len){ 32 if(c==0)return 1; 33 if(c>=len)return n+1; 34 int t=len-1; 35 while(t>=0&&(n&(1<<(t-1)))==0){ 36 t--; 37 } 38 return f(n-(1<<(len-1)),c-1,t)+sum[len-1][0][c]; 39 } 40 int solve(int n){ 41 if(n==0)return 1; 42 int k=1<<30,len=31; 43 while((k&n)==0){ 44 k>>=1;len--; 45 } 46 int l=len-1; 47 while(l>=0&&(n&(1<<(l-1)))==0){ 48 l--; 49 } 50 return t[len-1]+f(n-(1<<(len-1)),(len-2)/2,l); 51 } 52 //bool Is_round(int n){ 53 // int k=1,a=0,b=0; 54 // while(k<=n){ 55 // if(k&n)a++; 56 // else b++; 57 // k<<=1; 58 // } 59 // if(a<=b)return true; 60 // return false; 61 //} 62 //int test(int n){ 63 // int count=0; 64 // for(int i=1;i<=n;i++){ 65 // if(Is_round(i))count++; 66 // } 67 // return count+1; 68 //} 69 int main(){ 70 CalC(); 71 CalT(); 72 int n; 73 // while(cin>>n){ 74 // cout<<solve(n)<<‘ ‘<<test(n)<<endl; 75 // } 76 cin>>start>>finish; 77 cout<<solve(finish)-solve(start-1)<<endl; 78 return 0; 79 }

poj 3252 Round Numbers(數學)