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

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/RockyHOO1209/article/details/78783843

思路:

做法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好像有一道类似的更简单一点。。有空给做了
展开阅读全文

没有更多推荐了,返回首页