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



数字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.

posted @ 2012-06-18 22:38  max_xbw  阅读(667)  评论(0编辑  收藏  举报