牛客小白月赛39 G 线性筛素数+离线+树状数组

题目链接

G-冷静_牛客小白月赛39 (nowcoder.com)

 

题意

有q(q<=3e6)组询问,每次给你n和k(n,k<=3e6),你需要回答在小于等于n的数中有多少个数可以表示为一些>=k的质数的乘积

 

思路

首先,由于q很大,n也很大,可以发现单次查询的时间复杂度必然要小于On

当你发现单次询问无论如何也无法化简时间,这时需要改变思路了。

查询O1:前缀和。但由于此题的k和n不固定,该方法行不通

查询Ologn:树状数组。

由此引出正解——

我们可以先预处理,筛出3e6以内的质数,可以顺势找出3e6内的每个数的最小的质因数,再离线读入所有的n,对其进行从小到大的排序,利用树状数组可以Ologn求出最小质因数>=k的n的个数

 

最后注意要按询问顺序输出答案,我们可以给结构体多加一维统计输入序号,标记一下即可

code

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define rrep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)
#define sc(x) scanf("%d",&(x))
#define scl(x) scanf("%lld",&(x))
#define pb push_back
using namespace std;
const int N = 3e6+10,mod = 1e9+7;
int cnt,q;
int p[300006],minp[N];
bool vis[N];
ll c[N];
struct node{
    int num;
    int k;
    int id;
    bool operator < (const node &aa)const{
        return num<aa.num;
    }
}a[N];
int n=3e6;
int ans[N];

int lowbit(int x){
    return x&-x;
}

void add(int i,int d){
    while(i<=n){
        c[i]+=d;
        i+=lowbit(i);
    }
}

ll sum(int i){
    ll res=0;
    while(i>0){
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}

void init(int n){
    memset(vis,0,sizeof(vis));
    cnt=0;
    for(int i=2;i<=n;i++){
        if(!vis[i]) p[++cnt]=i;
        for(int j=1;j<=cnt&&i*p[j]<=n;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
    rep(i,2,n){
        if(vis[i]==0){
            minp[i]=i;
            continue;
        }
        rep(j,1,cnt){
            if(i%p[j]==0){
                minp[i]=p[j];
                break;
            }
        }
    }
    
}

int main(){
    init(3e6);
//    sc(q);
//    rep(i,1,q) cout<<i<<" "<<minp[i]<<endl;
    sc(q);
    rep(i,1,q) sc(a[i].num),sc(a[i].k),a[i].id=i;
    sort(a+1,a+1+q);
    int num=1;
    rep(i,1,q){
        if(a[i].num>num){
            rep(j,num+1,a[i].num){
                add(minp[j],1);
            }
            num=a[i].num;
        }
        if(a[i].k==1){
            ans[a[i].id]=sum(n);
        }
        else ans[a[i].id]=sum(n)-sum(a[i].k-1);
    }
    rep(i,1,q){
        printf("%d\n",ans[i]);
    }
    return 0;
} 
View Code

 

posted @ 2021-10-23 00:16  starlightlmy  阅读(52)  评论(0)    收藏  举报