找回密码
 欢迎注册
查看: 49163|回复: 13

[求助] 求因子个数的问题

[复制链接]
发表于 2011-11-9 11:55:41 | 显示全部楼层 |阅读模式

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

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

×
有这样一个问题: 求一个形如这样的数:$\frac{n(n+1)}{2}$ 的因子个数。 比如 1+2+3 = 6 = 3*(3+1)/2 这个数的因子是: 1,2,3,6总共4个 对于一个一般的形如上面所说的数,如果才能快速计算出其因子的个数呢? 我的计算方法没任何技巧,比较慢:
  1. for(i=1;;i++)
  2. {
  3. k = 0;
  4. for(j=1;j<=i*(i+1)/2;j++)
  5. {
  6. if((i*(i+1)/2)%j==0)
  7. {
  8. k++;
  9. }
  10. if(k>=500)
  11. {
  12. cout << "the number is : " << i*(i+1)/2;
  13. break;
  14. }
  15. }
  16. }
复制代码
我是计算因子个数超过500个的时候,这个数是多少。这个程序对于比较小的数还可以,对于稍微大一点的数,就算不出来了。我是对于
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-11-9 13:23:49 | 显示全部楼层
32位系统,整数的最大值是max_uint=2^32-1=4294967295 若 n*(n+1)/2
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-11-9 15:27:15 | 显示全部楼层
代码完成,可在1秒内检查完所有的数。最多有1024个因子 第一个含有1024个因子的数是73359, 73359*(73359+1)/2 有 1024 个因子
  1. // URL: http://bbs.emath.ac.cn/redirect.php?tid=3786&goto=lastpost#lastpost
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <math.h>
  5. #include <memory.h>
  6. typedef unsigned long DWORD;
  7. typedef unsigned char BYTE;
  8. // 一定范围内质数的个数
  9. // 10 4
  10. // 100 25
  11. // 1,000 168
  12. // 10,000 1,229
  13. // 100,000 9,592
  14. // 1,000,000 78,498
  15. // 10,000,000 664,579
  16. // 100,000,000 5,761,455
  17. // 1,000,000,000 50,847,534
  18. // 10,000,000,000 455,052,511
  19. // 100,000,000,000 4,118,054,813
  20. // 1,000,000,000,000 37,607,912,018
  21. // 10,000,000,000,000 346,065,536,839
  22. // 100,000,000,000,000 3,204,941,750,802
  23. // 1,000,000,000,000,000 29,844,570,422,669
  24. // 10,000,000,000,000,000 279,238,341,033,925
  25. // 100,000,000,000,000,000 2,623,557,157,654,233
  26. // 1,000,000,000,000,000,000 24,739,954,287,740,860
  27. // 估计x 范围内的质数的个数, 欧拉公式 pi(x)=x /( ln(x));
  28. // 经过测试,
  29. // 在1-1百万之间,相邻2个质数的最大差为114,这两个质数分别为492113,492227
  30. // 在1-1千万之间,相邻2个质数的最大差为154,这两个质数分别为4652353,4652507
  31. // 在1-3千万之间,相邻2个质数的最大差为210,这两个质数分别为20831323,20831533
  32. // 在1-1亿之间, 相邻2个质数的最大差为220,这两个质数分别为47326693,47326913
  33. #define MAX_PRIME 302
  34. struct FAC_ARR_ST
  35. {
  36. int fc;
  37. struct
  38. {
  39. DWORD p;
  40. int e;
  41. }arr[10]; //2^32以内的数最大9个素因子
  42. };
  43. struct FAC_ARR_ST g_facTab;
  44. void clear_facTab()
  45. {
  46. g_facTab.fc=0;
  47. memset(g_facTab.arr,0,sizeof(g_facTab.arr));
  48. }
  49. void add_to_facTab(DWORD p)
  50. {
  51. int i;
  52. int bfind=0;
  53. for (i=0;i<g_facTab.fc;i++)
  54. {
  55. if ( g_facTab.arr[ i ].p==p)
  56. {
  57. g_facTab.arr[ i ].e++;
  58. bfind=1;
  59. break;
  60. }
  61. }
  62. if ( !bfind )
  63. {
  64. g_facTab.arr[g_facTab.fc].p=p;
  65. g_facTab.arr[g_facTab.fc].e=1;
  66. g_facTab.fc++;
  67. }
  68. }
  69. //**********************************************
  70. // n 不能大于L2 cache,否则效能很低
  71. DWORD Sift32(DWORD n,DWORD *primeTab)
  72. // 对0到n 之间(不包括n)的数进行筛选,返回质数的个数
  73. //**********************************************
  74. {
  75. BYTE *pBuff= new BYTE[n];
  76. if (pBuff==NULL)
  77. return 0;
  78. DWORD i,sqrt_n,p;
  79. DWORD pn;
  80. //----------------------------
  81. sqrt_n=(DWORD)(sqrt(n)+1);
  82. while (sqrt_n * sqrt_n >=n)
  83. sqrt_n--;
  84. memset(pBuff,1,n*sizeof(BYTE));
  85. *pBuff=0;
  86. *(pBuff+1)=0; //1不是质数
  87. *(pBuff+2)=1; //2是质数
  88. for ( i=4;i<n;i+=2) //筛去2的倍数,不包括2
  89. *(pBuff+i)=0;
  90. for (i=3;i<=sqrt_n;) //i 是质数
  91. {
  92. for (p=i*i;p<n; p+=2*i)
  93. *(pBuff+p)=0; //筛去i 的奇数倍
  94. i+=2;
  95. while ( *(pBuff+i)==0 )
  96. i++; //前进到下一个质数
  97. }
  98. pn=0; //素数个数
  99. if ( primeTab==NULL)
  100. {
  101. for (i=2;i<n;i++)
  102. {
  103. if (pBuff[ i ])
  104. pn++;
  105. }
  106. }
  107. else
  108. {
  109. for (i=2;i<n;i++)
  110. {
  111. if (pBuff[ i ])
  112. {
  113. primeTab[pn++]=i;
  114. }
  115. }
  116. }
  117. delete[] pBuff;
  118. return pn;
  119. }
  120. void check_all(DWORD max_n)
  121. {
  122. DWORD *primeTab=NULL;
  123. DWORD primeCount;
  124. DWORD i,j,k;
  125. int f_c; //总的因子数
  126. int max_fc;
  127. //创建一个素数表
  128. primeCount=Sift32(MAX_PRIME,NULL); //得到MAX_PRIME以内的素数个数
  129. primeTab=(DWORD *) malloc(sizeof(DWORD)* (primeCount+1));
  130. Sift32(MAX_PRIME,primeTab);
  131. primeTab[primeCount]=2147483647; //设置一个栅栏
  132. max_fc=0;
  133. //-----------------------------------------
  134. for (i=2;i<=max_n;i++)
  135. {
  136. DWORD na[2];
  137. if (i & 1) //i是奇数
  138. { na[0]=i; na[1]=(i+1)/2;}
  139. else
  140. { na[0]=i/2; na[1]=i+1; }
  141. clear_facTab(); // n*(n+1)/2的素因子数表初始化为空
  142. for (j=0;j<2;j++)
  143. {
  144. DWORD n=na[j];
  145. DWORD r;
  146. // primeTab[primeCount]=2147483647,保证循环能够终止
  147. r=n;
  148. for (k=0; primeTab[k] * primeTab[k] <= n && r>1; )
  149. {
  150. DWORD prime=primeTab[k];
  151. if ( n % prime==0)
  152. {
  153. add_to_facTab(primeTab[k]); //增加素因子到素因子表 g_facTab
  154. r/=primeTab[k];
  155. }
  156. k++;
  157. }
  158. if (r>1)
  159. add_to_facTab(r);
  160. }
  161. f_c=1;
  162. for (j=0;j<g_facTab.fc;j++)
  163. f_c *= (g_facTab.arr[j].e +1);
  164. //printf("%u*(%u+1)/2 with %u factor\n",i,i,f_c);
  165. if (f_c >max_fc)
  166. {
  167. printf("%u*(%u+1)/2 with %u factor\n",i,i,f_c);
  168. max_fc=f_c;
  169. }
  170. }
  171. free(primeTab);
  172. }
  173. int main(int argc, char* argv[])
  174. {
  175. check_all(92681);
  176. return 0;
  177. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-11-9 15:43:01 | 显示全部楼层
有才
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2011-11-9 16:46:18 | 显示全部楼层
首先感谢liangbch,里面提到的算法很有用:
m=p1^e1 * p2^e2 * ... * pn^e5,则这个m的所有因数个数是(e1+1)*(e2+1)*... *(en+1)
我用这个也算了下,的确速度很快。我是对每个数,统计下其素因子个数,然后按照公式算。
  1. #include <iostream>
  2. using namespace std;
  3. void main()
  4. {
  5. int a[200],n,i,j,k,ans,answer,l,end;
  6. for(n=0;n<200;n++)
  7. {
  8. a[n] = 0;
  9. }
  10. for(i=1;;i++)
  11. {
  12. k = 0;
  13. answer = i*(i+1)/2;
  14. ans = i*(i+1)/2;
  15. for(j=2;j<=ans;j++)
  16. {
  17. if(ans%j == 0)
  18. {
  19. while(ans%j==0)
  20. {
  21. a[k]++;
  22. ans = ans / j;
  23. }
  24. k++;
  25. }
  26. }
  27. end = 1;
  28. for(l=0;l<k;l++)
  29. {
  30. end = (a[l]+1)*end;
  31. }
  32. if(end >= 500)
  33. {
  34. cout << "end is :"<< end << endl;
  35. cout << "answer is : " << answer << endl;
  36. break;
  37. }
  38. for(n=0;n<200;n++)
  39. {
  40. a[n] = 0;
  41. }
  42. }
  43. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-11-9 17:24:59 | 显示全部楼层
你这个求m的素因子的代码还是有待改进,在最坏情况下,求m的所有素因子的复杂度是sqrt(m)/ln(sqrt(m)),不必从2逐一试除到m
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-11-9 17:51:33 | 显示全部楼层
好厉害。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-11-9 20:13:21 | 显示全部楼层
看了一下楼主的代码,并将int 型变量改为unsigned long后,发现楼主的代码也只能检查到65535,当i>65535, 5楼第12行代码会发生整数溢出。
answer = i*(i+1)/2;
我的代码可检查到 92681。 对楼主的代码做了如下修改,并增加了时间花费检测,发现,当检测到65535时,我的程序用时为21.6毫秒,楼主的程序为2081毫秒。 1.修改变量定义,将int型改为unsigned long,增加数据范围。 2.屏蔽5楼的第36-38行。
36. // cout << "end is :"<< end << endl; 37. //cout << "answer is : " << answer << endl; 38. // break;
3. 将 “for(i=1;;i++)” 改为 “for(i=1;i<65536;i++)” 我的代码有少许修改, 1. 将3楼第210行改为“check_all(65535);“ 2.在3楼183行后增加 "if ( primeTab[k]>r) break",如果不修改此处,用时为22.1毫秒
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-11-9 20:23:18 | 显示全部楼层
3# 代码价值信息量很大! 需要花点时间好好咀嚼。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2011-11-9 20:27:23 | 显示全部楼层
楼上过奖了。关于筛法求素数和分解质因数,楼上亦可称为专家,对楼上来说,我的代码很很稀松平常,没什么值得学习的,不过对于初学者,应该具有参考价值。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

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

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

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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