题目来源:https://vjudge.net/problem/LightOJ-1197
【题意】
求a,b区间里的素数个数。
【思路】
第一时间,想到打表,心想到又遇见一道水题,,然后,很自然的去看数据范围,mmp,极限值,傻眼了。。。同时又看到b-a<=100000,一般这样的题,都是从小范围入手,于是就开始了探索。
结果,还是不会写,,于是就翻了博客,看了一半,迷迷糊糊,心想着学长的教诲,要把别人的变成自己的,于是凭着一知半解的感悟自己想,猛然间发现,打表的数字10^5不是随意定下的,因为可以看到他的平方刚好就是极限(差不多。。)。
然后想是不是根据1~10^5的素数表可以推出来想要得到的a,b之间的素数表,然后就发现可以,因为哦,假设a是1000005,那么对于素数2来说,1000006不是素数,1000008等等都不是素数,也就是用1000005/2==x,判断2*x是否为1000005,若是,则1000005不是素数,然后就这样一直往后推,若不是,也可以继续往后推。
但是呢,有一个问题就出现了,众所周知,打表的时候需要一个vis数组进行判断的,但是如果a超级大,开不了那么大的数组怎么办?
然后,就想啊,我们要求的只是a,b这一段的vis,为什么不把他们的数值同时减去a呢?
以下是两种代码:
都差不多啦。。。
【代码1】
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int INF=1e9;
typedef unsigned long long ll;
typedef long long LL;
const int maxn=1e5+10;
int prime[maxn];
bool vis1[maxn],vis2[maxn];
int l=0;
void init()
{
mem(vis1,0);
vis1[1]=1;
for(int i=2; i<=maxn; i++)
{
if(!vis1[i])
{
prime[l++]=i;
for(int j=2*i; j<=maxn; j+=i)
vis1[j]=1;
}
}
}
int main()
{
init();
int T,cases=1;
scanf("%d",&T);
while(T--)
{
LL a,b,ans=0;
scanf("%lld%lld",&a,&b);
if(b<=maxn-1)//相当于第二种代码里的a=1的特判
{
for(LL i=a; i<=b; i++)
{
if(!vis1[i])
ans++;
}
printf("**\n");
}
else
{
mem(vis2,0);
for(LL i=0; i<l&&prime[i]<=b; i++)
{
LL x=a/prime[i];
if(x*prime[i]<a)
x++;
for(LL j=x*prime[i]; j<=b; j+=prime[i])
{
if(j!=prime[i])
vis2[j-a]=1;
}
}
for(LL i=a; i<=b; i++)
if(!vis2[i-a])
ans++;
}
printf("Case %d: %lld\n",cases++,ans);
}
}
【代码2】
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int INF=1e9;
typedef unsigned long long ll;
typedef long long LL;
const int maxn=1e5+10;
int prime[maxn];
bool vis1[maxn],vis2[maxn];
int l=0;
void init()
{
mem(vis1,0);
vis1[1]=1;
for(int i=2; i<=maxn; i++)
{
if(!vis1[i])
{
prime[l++]=i;
for(int j=2*i; j<=maxn; j+=i)
vis1[j]=1;
}
}
}
int main()
{
init();
int T,cases=1;
scanf("%d",&T);
while(T--)
{
LL a,b,ans=0;
scanf("%lld%lld",&a,&b);
mem(vis2,0);
for(LL i=0; i<l&&prime[i]<=b; i++)
{
LL x=a/prime[i];
if(x*prime[i]<a)
x++;
for(LL j=x*prime[i]; j<=b; j+=prime[i])
if(j!=prime[i])
vis2[j-a]=1;
}
for(LL i=a; i<=b; i++)
if(!vis2[i-a])
ans++;
if(a==1)
ans-=1;
printf("Case %d: %lld\n",cases++,ans);
}
}