UVALive 6844 Combination(组合数学)

来源:互联网 发布:网络不可用是怎么回事 编辑:程序博客网 时间:2024/05/17 08:41

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=79610

题意:求for(int i = low ; i <= high ;i++) for(int j=0 ;j<= i; j++) C(i,j)%2==1的个数。

题解:组合数位奇数有个定理:n&m==m  =>  C(n,m)%2==1.  n&m==m,当且仅当m二进制位为1时n的二进制该位也为1,。

            这样我们算0-n ,可以将n转换成二进制,枚举每一位,如果是1的话,说明后面的可能情况为每位可为1 也可为0,然后

           再枚举1 的个数,更新ans.

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>using namespace std;typedef unsigned long long ll;int num[66];ll p2[66];ll C[66][66];void init() {    p2[0]=1;    for(int i=1; i<52; i++)p2[i]=p2[i-1]*2;    memset(C,0,sizeof C);    C[0][0]=1;    for(int i=1; i<50; i++) {        C[i][0]=1;        for(int j=1; j<=i; j++) {            C[i][j]=C[i-1][j]+C[i-1][j-1];        }    }}ll solve(ll a) {    if(a==-1)return 0;    if(a==0)return 1;    ll x=a;    int len=0;    while(x) {        num[len++]=x%2;        x>>=1;    }    ll res=0;    int h=0;///前面1的个数    for(int i=len-1; i>=0; i--) {        if(!num[i])continue;        for(int j=0; j<=i; j++) {///枚举1的个数            res+=C[i][j]*p2[j+h]; ///因为每个1可选可不选,所以要乘2^(j+h).        }        h++;    }    return res+p2[h];}int main() {#ifdef ONLINE_JUDGE#else    freopen("test.in","r",stdin);#endif    ll l,r;    init();    while(~scanf("%llu%llu",&l,&r)) {        if(!l&&!r)break;        printf("%llu\n",solve(r)-solve(l-1));    }    return 0;}


0 0
原创粉丝点击