这题就是一个素数筛再加上一个线段树。首先数据素数筛将每个最小素因子的倍数标记最小素因子(简单来讲就是把每个数最小素因子标记出来)然后再遍历每个数。线段树标记1-x-1中最小素因子小于当前最小素因子的数量。最后数组里就是1-x-1中符合标准的数字,最后输入再查询即可。这道题关键在于预先处理,处理好了这道题就很简单了。以下为A代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ffi;
const int maxn=1000005;
ffi node[maxn<<2];
ffi a[maxn],flag[maxn];
void pushup(int nd)
{
node[nd]=node[nd<<1]+node[nd<<1|1];
}
void build(int l,int r,int nd)
{
if(l==r)
{node[nd]=0;
return;}
int mid=(l+r)>>1;
build(l,mid,nd<<1);
build(mid+1,r,nd<<1|1);
pushup(nd);
}
void update(int pos,int l,int r,int nd)
{
if(l==r)
{
node[nd]+=1;
return;
}
int mid=(l+r)>>1;
if(mid<pos)update(pos,mid+1,r,nd<<1|1);
else update(pos,l,mid,nd<<1);
pushup(nd);
}
ffi query(int s,int e,int l,int r,int nd)
{
if(s<=l&&e>=r)
{
return node[nd];
}
ffi ans=0;
int mid=(l+r)>>1;
if(s<=mid)ans+=query(s,e,l,mid,nd<<1);
if(e>mid)ans+=query(s,e,mid+1,r,nd<<1|1);
return ans;
}
void getsum()
{
build(1,maxn,1);
update(1,1,maxn,1);
memset(a,0,sizeof(a));
memset(flag,0,sizeof(flag));
for(ffi i=2;i<=sqrt(maxn);i++)
{
for(ffi j=i;j<maxn;j+=i)
if(!flag[j])
{a[j]=i;flag[j]=1;}
}
for(ffi i=2;i<maxn;i++)
{if(a[i]==0)a[i]=i;
ffi tep=a[i];
a[i]=query(1,a[i],1,maxn,1);
update(tep,1,maxn,1);}
}
int main()
{
int t;scanf("%d",&t);
getsum();
while(t--)
{
ffi x;
scanf("%lld",&x);
printf("%lld\n",a[x]);
}
}
以下为标准题解