poj 3252 组合数

    主要考察组合数知识,初始化的时候参考公式
首先先推个公式,就是长度为len的Round Numbers的个数。
     长度为len,第一位肯定是1了。
     那么后面剩下 len-1位。
     如果len-1是偶数。
     那么  C(len-1,(len-1)/2+1)+C(len-1,(len-1)/2+2)+````C(len-1,len-1)
=   ( 2^(len-1)-C(len-1,(len-1)/2) )/2;
    如果len是奇数
   那么就是 (  2^(len-1) )/2
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 const int maxn=35;
 9 int m,t;
10 int c[maxn][maxn];
11 int bit[maxn];
12 void init()     //初始化组合数
13 {
14     c[0][0]=c[1][0]=c[1][1]=1;
15     for(int i=2;i<=33;i++)
16     {
17         c[i][0]=1;
18         for(int j=1;j<i;j++)
19             c[i][j]=c[i-1][j]+c[i-1][j-1];
20         c[i][i]=1;
21     }
22 }
23 int calc(int n) //求小于等于n的round数的和
24 {
25     if(n<=1)    return 0;
26     int len=0;
27     while(n>0)  //求出该数的二进制表示
28     {
29         if(n&1) bit[len++]=1;
30         else bit[len++]=0;
31         n>>=1;
32     }
33     int ans=0;
34     for(int i=len-1;i>0;i--)    //求出长度小于len的round数的和
35     {
36         if(i%2==0)ans+=((1<<(i-1)))/2;
37         else  ans+=((1<<(i-1))-c[i-1][(i-1)/2])/2;
38     }
39     int c1=0,c0=0;
40     for(int i=0;i<len;i++)
41     {
42         if(bit[i]==0)    c0++;
43         else c1++;
44     }
45     if(c0>=c1)  ans++;      //该数本身是round数
46     c1=1;c0=0;
47     for(int i=len-2;i>=0;i--)    //注意计数是从零开始的
48     {
49         if(bit[i]==1)   //该位可以变成零
50         {
51             for(int j=i;j>=0&&j+c0+1>=i-j+c1;j--)    ans+=c[i][j];   //j是准备添加的0的数目
52             c1++;
53         }
54         else c0++;
55     }
56     return ans;
57 }
58 int main()
59 {
60     int i,j,k;
61     init();
62     int a,b;
63     //freopen("1.in","r",stdin);
64     while(scanf("%d%d",&a,&b)!=EOF)
65     {
66         printf("%d\n",calc(b)-calc(a-1));
67     }
68     return 0;
69 }

 

posted @ 2015-03-06 15:06  miao_a_miao  阅读(169)  评论(0编辑  收藏  举报