1. 素数统计
(pcount.pas/.c/.cpp)
【问题描述】
小tan的老师揣谙戈给同学们布置了一道题,要求统计给定区间内素数的个数。“这不是很简单吗?”小tan忍不住说。揣谙戈冷笑一下说:“等你们看到题目就知道了。”便转身离去。
果然,小tan被那极大的区间吓怕了,现在是你拯救她的时候。
【输入】
输入文件名为pcount.in。
输入一行两个正整数a和b,表示给定区间为[a,b]。
【输出】
输出文件名为pcount.out。
输出一个整数,表示区间内素数数量。
【输入输出样例】
pcount.in | pcount.out |
1 17 | 7 |
【数据范围】
对于30%的数据,有n<m≤1,000;
对于60%的数据,有n<m≤1,000,000;
对于100%的数据,有n<m<2^31,m-n≤1,000,000。
解题报告:
看到这么大的数据,果然是被吓怕了。前一天才学的数论,这一次考试就考了两道题,虽然我只做了两道题。先说说这道题吧,这道题自己做的时候心想,反正都得不全分,干脆就把数组定小一点,得个六七十分吧。于是开始暴力筛数法,把1~m和1~n的素数都筛出来,然后相减,只不过要注意n是素数的情况,ans--;于是得了70。
正解:这么大的数组肯定不行,所以需要下标(数组)平移,把n~m之间的及大于sqrt(m)的平移到0~m-n的下标。然后扫一遍这个区间,把ans加上。但要注意特殊情况:n==1的时候,ans--;
值得注意的是:循环时把 j 定义为long long,因为当m很大时,i * i+ i 就超出了int的范围,这个时候会变为负数,然后无限循环,最后一组数据就超时了。
代码附下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 long long n,m,ans; 6 const int maxn=1000005; 7 bool vis1[maxn],vis2[maxn]; 8 int main() 9 { 10 freopen("pcount.in","r",stdin); 11 freopen("pcount.out","w",stdout); 12 cin>>n>>m; 13 long long mid=sqrt(m)+1; 14 for (long long i=2;i<=mid;i++) 15 { 16 if (!vis1[i]) 17 { 18 for (long long j=i*i;j<=mid;j+=i)//long long 19 vis1[j]=1; 20 for (long long j=n/i*i;j<=m;j+=i) 21 if (j>i&&j>=n) vis2[j-n]=1; 22 } 23 } 24 for (int i=0;i+n<=m;i++) 25 if (!vis2[i]) ans++; 26 if (n==1) ans--; 27 cout<<ans; 28 return 0; 29 }