Help Hanzo (数论(素数(打表进阶(任意段区域打表)))))

来源:互联网 发布:trados翻译软件官方 编辑:程序博客网 时间:2024/06/10 06:38

题目来源: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);    }}
原创粉丝点击