1. 程式人生 > >poj 3252 Round Numbers (楊輝三角求組合數)

poj 3252 Round Numbers (楊輝三角求組合數)

題目連結:poj 3252

題意:給出範圍為 [a , b] 的區間,問在這區間內的每個數字,假如它的二進位制位0的個數大於1的個數,就說明它是Round Numbers,問你有多少個Round Numbers數?

題解:首先楊輝三角求組合數學,見程式碼。

 

///此題就是個組合數學題,二項式和為2^n,
///但這題卡我的是求組合數那裡,我剛想的是按一般方法求,
///但因為最多有32位,會爆,網上說用楊輝三角,一想是哦,
///做完這題又學會了用楊輝三角求組合數

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

typedef long long LL;

LL C[35][35];
int bits[35];

void init() ///楊輝三角求組合數
{
    C[0][0]=C[1][0]=C[1][1]=1;

    for(int i=2;i<33;i++)
    {
        C[i][0]=1;
        for(int j=1;j<i;j++)
         C[i][j]=C[i-1][j-1]+C[i-1][j];
        C[i][i]=1;
    }
}

LL solve(int n)
{
    if(n<=1) return 0;

    int len=0;

    while(n)
    {
        if(n&1) bits[++len]=1;
        else bits[++len]=0;
        n>>=1;
    }


    LL ans=0;

    ///當i為偶數時,說明在i-1位中,可以取C[i-1][i/2]+C[i-1][i/2+1]+...+C[i-1][i]
    ///當i為奇數時,說明在i-1位中,可以取C[i-1][i/2]+C[i-1][i/2+1]+...+C[i-1][i],比偶數多一個最中間的
    for(int i=len-1;i>=2;i--)
    {
        if(i%2==0) ans+=((1<<(i-1)))/2; ///二項式和的一半
        else ans+=((1<<(i-1))-C[i-1][(i-1)/2])/2;

    }


    int cnt1=0,cnt0=0;
    for(int i=1;i<=len;i++)
    {
        if(bits[i]==0) cnt0++;
        else cnt1++;
    }

    if(cnt0>=cnt1) ans++; ///本身就是

    cnt0=0;cnt1=1; ///計數0 1 的個數

    for(int i=len-1;i>=1;i--)
    {
        if(bits[i]==1){ ///後面有i-1位,我們把第i為看做0

            for(int j=i-1;j>=0&&j+cnt0+1>=(i-1)-j+cnt1;j--) ///在i-1位中取j個0
                ans+=C[i-1][j];
            cnt1++;
        }
        else
            cnt0++;
    }

    return ans;

}

int main()
{
    int a,b;

    init();

    while(~scanf("%d%d",&a,&b))
    {
        printf("%lld\n",solve(b)-solve(a-1));
    }
    return 0;
}