//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))