GOJ 1452(数论+前缀和查询)

来源:互联网 发布:什么手机壳防摔 知乎 编辑:程序博客网 时间:2024/06/05 16:27

思路:

做法1:
离线暴力打表存起来,然后再询问。
做法2:
找到5e5之内的素数,两两相乘,再结合素数的立方,排个序,再询问。
一个有四个因子的整数要么是一个素数的立方,要么是两个不同素数的乘积。
做法3:
枚举每个数,对它的倍数进行计数。那么最后要求计数器为4的数字。


开始用第一种方法发做,一直TLE,感觉应该是最后判断因子数是4的时候超时了,后来看了下题解,选择第二种方法做。

证明:第一种情况很明显,就i是1和本身再加上两个质因子(任何一个合数都能表示成几个质因子的乘积)。第二种情况,即三个素数的乘积。因为相同的两个素数乘出来的数一定是只有三个因数的。(一个素因子加1和本身),也就是说它不能分解成除1和本身外的另外两个因数相乘,即可以看作乘出来的数是不可分的。则a可拆成(p*p) p a 1四个因子。

所以只要把范围内的所有素数两两相乘和素数的立方存起来,查询一遍就可以。

(这里有个一直模糊不清的概念,就是1000ms约等于10^8,开始以为是1e9,一直没找到TLE的地方)

 

#include<cstdio>#include<cstring>#include<vector>#include<algorithm>#include<stdlib.h>#include<iostream>#include<map>using namespace std;const int maxn=5e5;int n,a,b,prime[maxn],primesize,cnt,cnt2,num[maxn];bool isprime[maxn];vector<int> v;map<int,int> m;void getlist(int listsize){    memset(isprime,1,sizeof(isprime));    isprime[1]=false;    for(int i=2;i<=listsize;i++){        if(isprime[i])            prime[++primesize]=i;        for(int j=1;j<=primesize&&i*prime[j]<=listsize;j++){            isprime[i*prime[j]]=false;            if(i*prime[j]==0)                break;        }    }}void init(){    //cout<<primesize<<endl;    cnt=0;    memset(num,0,sizeof(num));    for(int i=1;i<=primesize;i++){        if(prime[i]>=maxn)            break;        for(int j=1;j<=primesize;j++){        if(i==j)        continue;        if(prime[i]*prime[j]>maxn)            break;        int ans=prime[i]*prime[j];        m[ans]=1;        }    }    for(int i=1;i<primesize;i++){        int ans=prime[i]*prime[i]*prime[i];        if(ans>maxn)            break;        m[ans]=1;    }    for(int i=1;i<=maxn;i++){        if(m[i]==1)        num[i]=num[i-1]+1;        else        num[i]=num[i-1];    }}int main(){    //freopen("out.txt", "w", stdout);    getlist(maxn);    init();    while(scanf("%d",&n)!=EOF){        while(n--){            cnt2=0;            scanf("%d%d",&a,&b);            //cout<<num[a]<<" "<<num[b]<<endl;            if(m[a]==1)                cnt2=num[b]-num[a]+1;            else                cnt2=num[b]-num[a];            //memset(num,0,sizeof(num));            /*for(int i=a;i<=b;i++){             if(m[i]==1)                cnt++;            }*/        printf("%d\n",cnt2);        }    }    return 0;}
cf好像有一道类似的更简单一点。。有空给做了

阅读全文
0 0
原创粉丝点击