找回密码
 欢迎注册
查看: 28764|回复: 21

[求助] 组合数的模运算

[复制链接]
发表于 2011-12-27 15:47:02 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
求 C(n,m) mod(M) 的算法。 其中n,m,M 均在int型范围内。 速度越快,内存占用越少越好, 看有没有两个都在O(n)尺度以内的算法。 问题背景:http://poj.grids.cn/practice/4036/
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-12-27 20:03:57 | 显示全部楼层
终于搞定了 平均的时间复杂度大致是 O(m),(mhttp://poj.grids.cn/practice/4036/statistics/
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-12-28 09:00:34 | 显示全部楼层
这么厉害,祝贺祝贺! 我想应该用到一些数学上的优化以及内嵌汇编吧?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-12-28 10:42:40 | 显示全部楼层
3# gxqcn 没有什么数学方法,就是模拟了一下最基础的约分化简过程。 应该还能优化的
  1. #include <stdio.h>
  2. #define MOD 10007
  3. int gcd(int m,int n)
  4. {
  5. int t ;
  6. while(m!=0)t=m,m=n%m,n=t ;
  7. return n ;
  8. }
  9. int binomialMod(int k,int n,int mod)
  10. {
  11. int c,g,ii,jj,p[n],q[n];
  12. /*C(k,n)= p1/q1*p2/q2*p3*q3....pn*qn */
  13. for(ii=0;ii<n;ii++)p[ii]=k-ii ;
  14. for(ii=n;ii>=1;ii--)
  15. {
  16. c=k%ii ;
  17. g=gcd(p[c],ii);
  18. p[c]/=g ;
  19. q[ii-1]=ii/g ;
  20. /*when ii<n/2, there are more reduction work */
  21. if(q[ii-1]!=1)
  22. {
  23. jj=0 ;
  24. while(q[ii-1]!=1&&c+jj<n)
  25. {
  26. c=k%q[ii-1];
  27. g=gcd(p[c+jj],q[ii-1]);
  28. p[c+jj]/=g ;
  29. q[ii-1]/=g ;
  30. jj+=g ;
  31. }
  32. }
  33. }
  34. c=1 ;
  35. for(ii=0;ii<n;ii++)
  36. {
  37. c*=p[ii];
  38. c%=mod;
  39. }
  40. return c ;
  41. }
  42. int powMod(int a,int pow,int mod)
  43. {
  44. int ii=0,s=1 ;
  45. while(++ii<=pow)s*=a,s%=mod ;
  46. return s ;
  47. }
  48. int main()
  49. {
  50. int a,b,k,n,m,ii,s ;
  51. scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
  52. a%=MOD ;
  53. b%=MOD ;
  54. s=1 ;
  55. s*=powMod(a,n,MOD);
  56. s*=powMod(b,m,MOD);
  57. s%=MOD ;
  58. s*=binomialMod(k,n,MOD);
  59. s%=MOD ;
  60. printf("%d",s);
  61. return 0 ;
  62. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-12-29 08:25:58 | 显示全部楼层
上面 Line 49 中的“s*=a” 恐有溢出风险吧?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-12-29 10:13:13 | 显示全部楼层
5# gxqcn 老大说的对。 呵呵,这题竟然被我蒙混过关了, 。 ========= 另外,如果指数比较大的话,一个一个的乘还会很慢。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-12-29 10:14:50 | 显示全部楼层
其实现将M因子分解是不错的方法,花费时间也不大,不会超过O(sqrt(M)) 然后计算M每个素因子在C(n,m)的次数,在然后计算因子乘积关于M(或其某个因子)的余数即可
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-12-29 10:18:15 | 显示全部楼层
6# wayne 上面的 binomialMod,powMod 函数仅对 MOD小于 sqrt(MAX_INT) 有效,而题目的MOD是 10007。
  1. int powMod(int a,int pow,int mod){
  2. if (pow==0) return 1;
  3. a%=mod;
  4. int s= powMod(a*a, pow/2, mod);
  5. if (pow%2 !=0) s*=a,s%=mod;
  6. return s;
  7. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-12-29 10:26:52 | 显示全部楼层
7# mathe 如果 M是素数,而且比较大,比如10007,该怎么考虑
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-12-29 10:30:18 | 显示全部楼层
感觉在INT范围内,计算两个INT的乘积的模,还需要单独考虑
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-22 04:54 , Processed in 0.025845 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表