组合数 题解

【问题描述】

定义C(N,K)表示从N个元素中不重复地选取K个元素的方案数。判断C(N,K)的奇偶性?

【输入】

第1行:一个正整数t,表示数据的组数。

第2~2+t-1行:两个非负整数N和K。(保证k<=n)

【输出】

每一组输入,如果C(N,K)是奇数则输出1,否则输出0。

【输入输出样例】

 

parity.in

parity.out

3

1 1

1 0

2 1

1

1

0

【数据规模】

对于30% 的数据,n<=10^2 t<=10^4

对于50% 的数据,n<=10^3 t<=10^5

对于100%的数据,n<=10^8 t<=10^5

 

 

预备知识


C(n, 0) = C(n, n)
= 1 (n > 0;)

C(n, k) = C(n − 1, k − 1) + C(n − 1, k) (0 < k < n)






算法一



有了预备知识里面的公式,我们可以得到一个最简单的算法。



先预处理算出所有的C(n,k)。



然后再读入,输出。



但是这样会产生一个问题,当n比较大的时候,C(n,k)会超出longint的范围。



解决方法?高精度!。



由于高精度的速度限制,所以这个算法只能过30%的点。






算法二



观察题目输出,其实就是输出C(n,k)mod 2=.这样可以运用同余算术的性质。



(a + b)mod k=((a
mod k)+(b mod k))mod k



(由于是mod 2,还可以写成and 1,利用位运算加速)



原式变为:



C(n, k) = (C(n
1, k − 1) + C(n − 1, k)) mod 2 (0 < k < n)



这样好多了,可以过50%的点。






算法三



直接的递推算法还可以优化嘛?找不出了。那我们掉换思路,从规律入手。



将前面的情况全部打印出来,我们可以发现。



其实就是一个2^k*2^k的三角形分解为四个2^(k-1)*2^(k-1)的三角形,中间一个三角形全为0,



余下三个三角形继续分解。详见程序和下面的附表



这个规律比较严格的描述是这样的,设N=XaXa-1Xa-2…X1(2),K=YbYb-1Yb-2…Y1(2)



(即用二进制表示)C(n,k)为偶的充分必要条件是存在i使得Xi<Yi



这样可以通过100%的点。






附表:n=32的情况(注:为了整齐0写成00,1写成11)



11



1111



110011



11111111



1100000011



111100001111



11001100110011



1111111111111111



110000000000000011



11110000000000001111



1100110000000000110011



111111110000000011111111



11000000110000001100000011



1111000011110000111100001111



110011001100110011001100110011



11111111111111111111111111111111



1100000000000000000000000000000011



111100000000000000000000000000001111



11001100000000000000000000000000110011



1111111100000000000000000000000011111111



110000001100000000000000000000001100000011



11110000111100000000000000000000111100001111



1100110011001100000000000000000011001100110011



111111111111111100000000000000001111111111111111



11000000000000001100000000000000110000000000000011



1111000000000000111100000000000011110000000000001111



110011000000000011001100000000001100110000000000110011



11111111000000001111111100000000111111110000000011111111



1100000011000000110000001100000011000000110000001100000011



111100001111000011110000111100001111000011110000111100001111



11001100110011001100110011001100110011001100110011001100110011



1111111111111111111111111111111111111111111111111111111111111111



110000000000000000000000000000000000000000000000000000000000000011









对组合数C(n,k)
(n&gt;=k):将n,k分别化为二进制,若某二进制位对应的n为0,而k为1 ,则C(n,k)为偶数;否则为奇数。

  组合数的奇偶性判定方法为:

  结论:

  对于C(n,k),若n&k == k 则c(n,k)为奇数,否则为偶数。

  证明:

  利用数学归纳法:

  由C(n,k) =
C(n,k-1) + C(n-1,k-1);

  对应于杨辉三角:

  1

  1 2 1

  1 3 3 1

  1 4 6 4 1

  ………………

  可以验证前面几层及k = 0时满足结论,下面证明在C(n-1,k)和C(n-1,k-1) (k &gt;
0) 满足结论的情况下,

  C(n,k)满足结论。

  1).假设C(n-1,k)和C(n-1,k-1)为奇数:

  则有:(n-1)&k
== k;

  (n-1)&(k-1)
== k-1;

  由于k和k-1的最后一位(在这里的位指的是二进制的位,下同)必然是不同的,所以n-1的最后一位必然是1

  。

  现假设n&k == k。

  则同样因为n-1和n的最后一位不同推出k的最后一位是1。

  因为n-1的最后一位是1,则n的最后一位是0,所以n&k != k,与假设矛盾。

  所以得n&k != k。

  2).假设C(n-1,k)和C(n-1,k-1)为偶数:

  则有:(n-1)&k
!= k;

  (n-1)&(k-1)
!= k-1;

  现假设n&k == k.

  则对于k最后一位为1的情况:

  此时n最后一位也为1,所以有(n-1)&(k-1) == k-1,与假设矛盾。

  而对于k最后一位为0的情况:

  则k的末尾必有一部分形如:10; 代表任意个0。

  相应的,n对应的部分为: 1{*}*; *代表0或1。

  而若n对应的{*}*中只要有一个为1,则(n-1)&k == k成立,所以n对应部分也应该是10。

  则相应的,k-1和n-1的末尾部分均为01,所以(n-1)&(k-1) == k-1 成立,与假设矛盾。

  所以得n&k != k。

  由1)和2)得出当C(n,k)是偶数时,n&k != k。

  3).假设C(n-1,k)为奇数而C(n-1,k-1)为偶数:

  则有:(n-1)&k
== k;

  (n-1)&(k-1)
!= k-1;

  显然,k的最后一位只能是0,否则由(n-1)&k == k即可推出(n-1)&(k-1) == k-1。

  所以k的末尾必有一部分形如:10;

  相应的,n-1的对应部分为: 1{*}*;

  相应的,k-1的对应部分为: 01;

  则若要使得(n-1)&(k-1)
!= k-1 则要求n-1对应的{*}*中至少有一个是0.

  所以n的对应部分也就为 : 1{*}*; (不会因为进位变1为0)

  所以 n&k = k。

  4).假设C(n-1,k)为偶数而C(n-1,k-1)为奇数:

  则有:(n-1)&k
!= k;

  (n-1)&(k-1)
== k-1;

  分两种情况:

  当k-1的最后一位为0时:

  则k-1的末尾必有一部分形如: 10;

  相应的,k的对应部分为 : 11;

  相应的,n-1的对应部分为 : 1{*}0; (若为1{*}1,则(n-1)&k == k)

  相应的,n的对应部分为 : 1{*}1;

  所以n&k = k。

  当k-1的最后一位为1时:

  则k-1的末尾必有一部分形如: 01; (前面的0可以是附加上去的)

  相应的,k的对应部分为 : 10;

  相应的,n-1的对应部分为 : 01; (若为11,则(n-1)&k == k)

  相应的,n的对应部分为 : 10;

  所以n&k = k。

  由3),4)得出当C(n,k)为奇数时,n&k = k。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值