洛谷P1865 A%B Problem

题面:

 

 这道题很明显是一道数论的题目,涉及的内容主要为素数的问题。首先看数据范围,其实这道题的数据范围是很水的。因此在这里主要介绍2种方法。

法一,首先题目给出了给定区间右端点的最大值,因此我们对于每一个输入的l和r,要先进行判断其是否合法,只有合法的区间才能进一步处理。而合法的标准是右端点r<=m且左端点l>=1(注意这里要小心,不要想当然,题目中出了四个点来卡它)。

因此我们可以对于每一个给定的合法区间l到r,枚举l到r中的所有元素,依次判断该元素是否为素数。如果为素数,则cnt++。这里对于素数的判断我使用了O(√n)的试除法。很明显该方法时间复杂度过大。

代码(含注释):

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int n,m,i,l,r,h,cnt;
 5 inline bool prime(int n){//判断每一个数是否为素数
 6     if(n<2){//<2的数一定不是素数,要小心
 7         return false;
 8     }else{
 9         int j;
10         for(j=2;j*j<=n;j++){//进行枚举
11             if(n%j==0){//如果n有2~√n的质因子,则n一定非质
12                 return false;
13             }
14         }
15     }
16     return true;
17 }
18 int main(){
19     scanf("%d %d",&n,&m);
20     for(i=1;i<=n;i++){
21         scanf("%d %d",&l,&r);
22         if(r>m||l<1){//判断区间是否合法
23             printf("Crossing the line
");
24         }else{
25             cnt=0;//统计每个区间内的素数个数
26             for(h=l;h<=r;h++){
27                 if(prime(h)==true){
28                     cnt++;
29                 }
30             }
31             printf("%d
",cnt);
32         }
33     }
34     return 0;
35 }

分数:81分(完全没有想到!)

法二,既然法一出现了超时,那我们就要想方法进行优化。在法一中,TLE的主要原因便是对于同一个素数需要进行多次判断。而如果能够在一定的预处理基础上将O(√n)变成O(1),那么时间就加快了。

题目明显预先给出了r的最大值,目的即是启发我们进行预处理。因此我们可以在O(n)的时间复杂度内预先找出1~m中的质数(我使用了线性筛),然后进行寻找和统计。

代码(含注释):

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int n,m,i,j,l,r,h,cnt,num;
 5 int prime[100000005],v[100000005];
 6 int main(){
 7     scanf("%d %d",&n,&m);
 8     num=0;//质数数量
 9     for(i=2;i<=m;i++){
10         if(v[i]==0){//i是质数 
11             v[i]=i;//质数的最小质因子是他自己
12             prime[++num]=i;//记录质数 
13         }
14         for(j=1;j<=num;j++){//给当前的数i乘上一个质因子 
15             if(prime[j]>v[i]||prime[j]>m/i){
16                 break;//i有比prime[j]更小的质因子,或者超出n的范围 
17             }
18             v[i*prime[j]]=prime[j];
19         }
20     }
21     for(i=1;i<=n;i++){
22         scanf("%d %d",&l,&r);
23         if(r>m||l<1){
24             printf("Crossing the line
");
25         }else{
26             cnt=0;
27             for(h=1;h<=m;h++){
28                 if(prime[h]>=l&&prime[h]<=r){
29                     cnt++;
30                 }
31             }
32             printf("%d
",cnt);
33         }
34     }
35     return 0;
36 }

即可获得AC。

原文地址:https://www.cnblogs.com/qianr/p/13280052.html