HDOJ-2138+HDOJ-1215 素数查找、素数约数和公式问题[总结:筛选法]


 

How many prime numbers

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6628    Accepted Submission(s): 2160


Problem Description
  Give you a lot of positive integers, just to find out how many prime numbers there are.
 

 

Input
  There are a lot of cases. In each case, there is an integer N representing the number of integers to find. Each integer won’t exceed 32-bit signed integer, and each of them won’t be less than 2.
 

 

Output
  For each case, print the number of prime numbers you have found out.
 

 

Sample Input
3 2 3 4
 

 

Sample Output
2
 

 

Author
wangye
 

 

Source
 

 

Recommend
威士忌
 
 
 1 #include<iostream>

 2 #include<cmath>

 3 using namespace std;

 4 

 5 bool data[10000000];

 6 #define max 10000000

 7 

 8 bool dep(int num)

 9 {

10     int i;

11     for(i=2;i<sqrt(num);i++)

12     {

13         if(num%i==0)

14             return true;

15     }

16     return false;

17 }

18 

19 int main()

20 {

21     int i,j;

22     int num;

23     int count;

24     int number;

25     memset(data,0,sizeof(data));

26     for(i=2;i<=5000000;i++)

27     {

28         if(data[i]==0)

29             for(j=i+i;j<=10000000;j+=i)

30                 data[j]=1;

31     }

32     while(~scanf("%d",&num))

33     {

34         count=0;    

35         for(i=0;i<num;i++)

36         {

37             scanf("%d",&number);

38             if(number>=max)

39             {

40                 if(!dep(number))

41                     count++;

42             }

43             else if(!data[number])

44                 count++;

45         }            

46         printf("%d\n",count);

47     }

48     return 0;

49 }

 

 

 

 

筛选法核心:

for(i=2;i<=5000000;i++)
 {
  if(data[i]==0)
   for(j=i+i;j<=10000000;j+=i)
    data[j]=1;
 }

 


七夕节

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 17449    Accepted Submission(s): 5198


Problem Description
七夕节那天,月老来到数字王国,他在城门上贴了一张告示,并且和数字王国的人们说:"你们想知道你们的另一半是谁吗?那就按照告示上的方法去找吧!"
人们纷纷来到告示前,都想知道谁才是自己的另一半.告示如下:

HDOJ-2138+HDOJ-1215 素数查找、素数约数和公式问题[总结:筛选法]


数字N的因子就是所有比N小又能被N整除的所有正整数,如12的因子有1,2,3,4,6.
你想知道你的另一半吗?
 

 

Input
输入数据的第一行是一个数字T(1<=T<=500000),它表明测试数据的组数.然后是T组测试数据,每组测试数据只有一个数字N(1<=N<=500000).
 

 

Output
对于每组测试数据,请输出一个代表输入数据N的另一半的编号.
 

 

Sample Input
3 2 10 20
 

 

Sample Output
1 8 22
 

 

Author
Ignatius.L
 

 

Source
 
 
 
code:
  1 #include<iostream>

  2 #include<cmath>

  3 using namespace std;

  4 

  5 int data[500000];

  6 

  7 int main()

  8 {

  9     int n;

 10     int num;

 11     int result;

 12     int temp;

 13     int i,j;

 14     int tip=0;

 15     int p,q,r;

 16     memset(data,0,sizeof(data));

 17     for(i=2;i<=250000;i++)

 18     {                                                //筛选法

 19         if(data[i]==0)

 20             for(j=i+i;j<=500000;j+=i)

 21                 data[j]=1;

 22     }

 23     while(~scanf("%d",&n))

 24     {

 25         while(n--)

 26         {

 27             result=1;

 28             scanf("%d",&num);

 29             temp=num;

 30             r=1;

 31             for(i=2;i<=500000;i++)

 32             {

 33                 q=1;

 34                 if(!data[i])

 35                 {

 36                     p=1;

 37                     while(num%i==0)

 38                     {

 39                         p*=i;                               //公式

 40                         num/=i;

 41                         q+=p;

 42                     }

 43                     r*=q;

 44                     if(i>num)

 45                         break;

 46                 }

 47             }

 48             printf("%d\n",r-temp);

 49         }

 50     }

 51     return 0;

 52 }

 53 

 54 /*#include<iostream>

 55 #include<cmath>

 56 using namespace std;

 57 

 58 int count[50000];

 59 int flag[50000];

 60 int data[500000];

 61 

 62 int main()

 63 {

 64     int n;

 65     int num;

 66     int result;

 67     int temp;

 68     int i,j;

 69     int tip=0;

 70     memset(data,0,sizeof(data));

 71     for(i=2;i<=250000;i++)

 72     {

 73         if(data[i]==0)

 74             for(j=i+i;j<=500000;j+=i)

 75                 data[j]=1;

 76     }

 77     while(~scanf("%d",&n))

 78     {

 79         while(n--)

 80         {

 81             result=1;

 82             scanf("%d",&num);

 83             temp=num;

 84             memset(count,0,sizeof(count));

 85             memset(flag,0,sizeof(flag));

 86             for(i=2;i<=500000;i++)

 87             {

 88                 if(!data[i])

 89                 {

 90                     while(num%i==0)

 91                     {

 92                         flag[i]=1;

 93                         count[i]++;

 94                         num/=i;

 95                     }

 96                     if(flag[i])

 97                         result*=(pow(i,(count[i]+1))-1)/(i-1);               //公式:超时

 98                     if(i>num)

 99                         break;

100                 }

101             }

102             printf("%d\n",result-temp);

103         }

104     }

105     return 0;

106 }

107 */


纠结了有蛮久,刚开始没有用筛选法,而且后面的公式写的方法不对,导致了超时,提交了N次,命中率伤不起了。

 

 

看了下别人的解法,代码写的真整洁,真是自愧不如。

            法一:筛选法。。。。。空间换时间 

 1 #include <iostream>

 2 

 3 using namespace std;

 4 

 5 int wife[500010] = {0};

 6 

 7 int main( )

 8 {

 9     for( int i = 0; i < 500001; ++i )

10     {

11         wife[i] = 1;

12     }

13     for( int i = 2; i < 500001; ++i )

14     {

15         for( int j = 2; i * j < 500001; ++j )

16         {

17             wife[i*j] += j;

18         }

19     }

20     int T;

21     cin >> T;

22     while( T-- )

23     {

24         int N;

25         cin >> N;

26         cout << wife[N] << endl;

27     }

28     return 0;

29 }

 

                 法二:暴力

 

 

 1 #include <iostream>

 2 #include <cmath>

 3 

 4 using namespace std;

 5 

 6 int main( )

 7 {

 8     int T;

 9     cin >> T;

10     while( T-- )

11     {

12         int N;

13         cin >> N;

14         int t = sqrt( N );

15         int sum = 1;

16         for( int i = 2; i <= t; ++i )

17         {

18             if( N % i == 0 )

19             {

20                 sum += i;

21                 if( N / i != i )

22                 {

23                     sum += N / i;

24                 }

25             }

26         }

27         cout << sum << endl;

28     }

29     return 0;

30 }

 


 

    约数的求和公式:

    数360的约数有多少个?这些约数的和是多少?

    【分析与解】  360分解质因数:360=2×2×2×3×3×5=23×32×5;

    360的约数可以且只能是2a×3b×5c,(其中a,b,c均是整数,且a为0~3,6为0~2,c为0~1).

因为a、b、c的取值是相互独立的,由计数问题的乘法原理知,约数的个数为(3+1)×(2+1)×(1+1)=24.

    我们先只改动关于质因数3的约数,可以是l,3,32,它们的和为(1+3+32),所以所有360约数的和为(1+3+32)×2y×5w

    我们再来确定关于质因数2的约数,可以是l,2,22,23,它们的和为(1+2+22+23),所以所有360约数的和为(1+3+32)×(1+2+22+23)×5w

    最后确定关于质因数5的约数,可以是1,5,它们的和为(1+5),所以所有360的约数的和为(1+3+32)×(1+2+22+23)×(1+5).

    于是,我们计算出值:13×15×6=1170.

    所以,360所有约数的和为1170.

    评注:我们在本题中分析了约数个数、约数和的求法.下面我们给出一般结论:

    I.一个合数的约数的个数是在严格分解质因数之后,将每个质因数的指数(次数)加1后

所得的乘积.如:1400严格分解质因数后为23×52×7,所以它的约数有(3+1)×(2+1)×(1+1)=4×3×2=24个.(包括1和它自身)

Ⅱ.约数的和是在严格分解质因数后,将M的每个质因数最高次幂的所有约数的和相乘所得到的积.如:21000=23×3×53×7,所以21000所有约数的和为(1+2+22+23)×(1+3)×(1+5+52+53)×(1+7)=74880.

你可能感兴趣的:(总结)