poj-3219

26 篇文章 0 订阅
//184K  16MS    C++
#include <cstdio>
#include <cstring>

using namespace std;

int get2Num(int N) {
    int curLeft = N;
    int res = 0;
    while(curLeft >= 2) {
        curLeft /= 2;
        res += curLeft;
    }
    return res;
}

int n, m;
int main() {
    while(scanf("%d %d", &n, &m) != EOF) {
        int num1 = get2Num(n);
        int num2 = get2Num(m);
        int num3 = get2Num(n-m);
        if (num1 > num2 + num3) {
            printf("0\n");
        } else {
            printf("1\n");
        }
    }
}

一开始没思路,看了discuss以后才清楚:

因为C(n,m)表示为 : n!/(m!(n-m)!), 那么 只要知道 n! m! (n-m)! 里面还有多少个2的阶乘因子,只要n!中2的阶乘因子 大于 m! 和 (n-m)!的和,那么最后除数就一定可以表示为2*X, 那么就是偶数,否则,必然是奇数(因为除数不可能有2*X的形式)

其实编程之美讲过如何求n!中含有2的阶乘的个数的,不过题和本题不太一样:

对于一个数N, 要求其可以表示为2(b次方)*X(X不可能再被表示为2*Y的形式) 的数 b 就是其2的阶乘因子:

N!  = (2*0) *(2*0+1)*(2*1)*(2*1+1)*... * (2*X) * (2*X+1) *...*(2*n+1)<N是奇数>/(2*n)(N是偶数) 其中 n = N/2

那么在这些乘数里面,奇数(2*X + 1)不可能有2的阶乘因子, 而 偶数则必定至少有一个2的阶乘因子,先将每个偶数提取出一个2的因子,那么,就有 n = 2/N个 2了,

然后,之前的N变为:

(1*0) * (2*0+1) * (1*1)  *(2*1 + 1) * ... * (X) * (2*X + 1) * ... * (n)<N是偶数>/(2*n+1)<N是奇数>

那么在这个乘式里面,原来的2*X+1肯定还是没有2的阶乘因子,而 其余的 1 2 3 ... X ... n(N/2) 里面还是可能有阶乘因子的, 这时候,问题就变为从这个序列求2的阶乘因子个数了, 其实等于是一个范围变为1/2的同样问题,那么像之前操作,提取出 N/4个2, 余下的就变成了 1/4规模的问题, 可以这样一直递推求解,直到最后:

1...n(N/2) n已经 < 2了, 那么这时候这个序列只有 1, 一定不可能有2的阶乘因子,而因为也只有 1这个元素,因此也不存在进一步缩小的可能,这时候可以结束求解,

而不断累加的 N/2+N/4 + ... 就是最后N!里2的阶乘数量。

其实不光2, 像其他的素数阶乘因子都可以这么求(比如5)

而对于合数(比如10, 则可以求2和5的阶乘数量, 取两者小值(因为素数里只有2*5 == 10))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值