组合数奇偶性的判断 对于C(n,k),若n&k == k 则c(n,k)为奇数,否则为偶数。

本文介绍了一种快速判断组合数C(n,m)奇偶性的方法,通过分析n、m及(n-m)的二进制表示中1的个数,得出C(n,m)为奇数或偶数的条件。

最直观的方法就是计算一下,然后看它的奇偶性;但是这个时间以及数据范围上都不允许;
另外一种方法就是,对于给定C(n,m),检查n中2因子的个数与m和(n-m)中2因子个数和的关系,假设n!中2因子个数为a,m!中2因子个数为b,(n-m)!中2因子个数为c,则显然有a>=(b+c);并且当a==b+c时,一定为奇,否则为偶。题意转化为求a和b+c。求一个阶乘中含有的素因子i的个数的方法可以参见Knuth的具体数学,方法是显而易见的。但是有的时候,这种方法仍然太慢(比如TOJ的一道题目,要判断5000000次),更快的方法是什么呢?
方法三:由方法2可以很容易地看出,n!中含有2因子的个数等于(n-它的二进制形式中1的个数)(每除一次如果有1的话去掉一个1)。那么题意再次转化为求m,n-m以及n的二进制形式中1的个数。或者说,看n&m ?= m,这个呢,如果等于,那么也就意味着,所有m中为1的位置n一定为1,那么n-m就可以直接用二进制减,这样得到的差的二进制中1的个数加上m中二进制1的位数正好等于n中1的位数,由前面可以知道,这就是一个奇数

 

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

#include<stdio.h> #include<stdlib.h> /* 函数申明 */ int long_n(int n); int shuru(char *arr, int k, char *wei, int is_first); void jiami(char *arr, int k, int e, int n); /* 输入函数,记录从键盘输入的明文*/ int shuru(char *arr, int k, char *wei, int is_first) { int i; char ch; /*判断是否为第一分组的输入,如果是则获取输入的字符,否则就将上一分组最后获取的字符作为这一分组的第一个字符*/ if (is_first == 1) ch = getchar(); else ch = *wei; for (i = 0; (i < k) && (ch != '\n');i++) //获取字符直到获取到回车符为止 { arr[i] = ch; ch = getchar(); } *wei = ch; //最后获取到的字符准备作为下一分组的第一个字符 for (i = i; i < k; i++) arr[i] = 'a'; //输入不够一组个数的整数倍则补'a'(即为补零) if (ch == '\n') //接收到回车符返回0,否则为1 return 0; else return 1; } /*加密函数*/ void jiami(char *arr, int k, int e, int n) { int m = 0,c=1, i, j,t=0, shu,temp,num=0; int *array; /*Mi赋值过程*/ for (i = 0; i < k; i++) { temp = 1; for (j = 0; j < (k-i-1)*2; j++) temp = temp * 10; shu = (int)arr[i] - 97; m = m + temp * shu; } temp = e; /*获取e的二进制表达形式的位数*/ do{ temp = temp / 2; num++; } while (temp != 0); array = (int *)malloc(sizeof(int)*k); //申请动态数组 temp = e; /*动态数组存储e的二进制表达形式*/ for (i = 0; i < num; i++) { array[i] = temp % 2; temp = temp / 2; } /*避免出现天文数字的算法,详情见上文文字说明*/ for (i = num - 1; i >= 0; i--) { t = t * 2; temp = c*c; if (temp > n) { for (j = 0; temp - n*j >= 0; j++); j--; c = temp - n*j; } else c = temp; if (array[i] == 1) { t = t + 1; temp = c*m; if (temp > n) { for (j = 0; temp - n*j >= 0; j++); j--; c = temp - n*j; } else c = temp; } e = e / 2; } temp = c; i = 0; /*c的位数小于分组长度则在前补零*/ do{ temp = temp / 10; i++; } while (temp != 0); for (i; i < num; i++) printf("0"); printf("%d", c); } /*获取分组的长度*/ int long_n(int n) { int temp,i,j,k,shi,comp=0; temp = n; /*获取n的位数*/ for (i = 1; temp / 10 != 0; i++) { temp = temp / 10; } temp = i; /*若n的位数为基数*/ if (i % 2 != 0) { i = i - 1; return i; } /*若位数为偶数*/ else { for (j = 0; j < i/2; j++) { shi = 1; for (k = 0; k < temp - 2; k++) shi = shi * 10; comp = comp + shi * 25; temp = temp - 2; } if (comp <= n) return i; else { i = i - 2; return i; } } } /*主函数*/ int main() { int p, q, e, d, n, fai_n, k, i,is_first=1; char ch,*arr,wei='a'; printf("请输入p、q、e值,用空格间隔开\n"); scanf("%d%d%d", &p, &q, &e); //从键盘获取p、q、e值 n = p*q; fai_n = (p-1)*(q-1); //Φ(n) for (k = 0; (k*n + 1) % e != 0; k++); if ((k*n + 1) % e == 0) d = (k*n + 1) / e; //d * e ≡ 1 (mod Φ(n)) k = long_n(n); k = k / 2; //分组的长度 ch = getchar(); //缓冲回车符 arr = (char *)malloc(sizeof(char)*k); //申请动态数组 printf("请输入明文\n"); while (1) { i=shuru(arr,k,&wei,is_first); //调用输入字符的函数,接收到回车符返回0,否则为1 is_first = 0; //第一分组录入结束设为0 jiami(arr,k,e,n); //调用加密函数 if (i == 0) //接收到返回值为0跳出循环 break; } printf("\n"); return 0; } 修改这段代码,使他可以在pycharm中运行
03-26
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值