3463: 组合数-【2014暑期训练】T1Day1T2

内存限制:256 MB 时间限制:1 S
题面:传统 评测方式:文本比较 上传者:
提交:2 通过:2

题目描述

1. 组合数

【问题描述】

定义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…X12),K=YbYb-1Yb-2…Y12

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

这样可以通过100%的点。

 

附表:n=32的情况(注:为了整齐0写成001写成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。