分析
注意到本题用到了常用的一个套路:对 \(b\) 是否大于 \(2\) 分类讨论。
因为 \(b>2\) 也就是 \(b\ge3\) 时 \(a\le10^6\),所以考虑把 \(3\times10^6\)(因为有 \(k\) 的存在)前的质数筛出来,暴力找到 \(a^b\) 加入统计答案的 set(\(2^{60}>10^{18}\),因此 \(b\le59\))。
接下来考虑 \(b=2\) 的时候,由于 \(a^2\) 增长迅速,所以不需要枚举很多的 \(a\)。从 \(\lceil\sqrt{n}\rceil\) 开始枚举约 \(1000\) 个数的时候就可以了。
最后先把 set 中小于等于 \(n\) 的数 erase 掉,然后再 erase 掉前 \(k-1\) 个元素,再输出 set 中头元素的值就可以了。注意经常判断一下当前的数是否超过 \(10^18\)。
AC Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
set<int> st;
bool isp[5000010];
int pri[5000010],cnt=0;
void init(int n)
{
memset(isp,1,sizeof isp);
isp[0]=isp[1]=0;
for(int i=2;i<=n;i++)
{
if(!isp[i]) continue;
pri[++cnt]=i;
for(int j=i*i;j<=n;j+=i) isp[j]=0;
}
}
int ispr(int k)
{
for(int i=2;i*i<=k;i++) if(k%i==0) return 0;
return 1;
}
signed main()
{
int n,k;
cin>>n>>k;
init(3e6);
for(int i=1;i<=cnt;i++)
{
int b=pri[i],p=1;
for(int j=1;j<=cnt;j++)
{
while(p<pri[j])
{
p++;
b*=pri[i];
if(b>1e18) goto t;
}
st.insert(b);
}
t:;
}
int tp=ceil(sqrt(n));
for(int i=1;i<=1000;i++)
{
if(tp*tp>1e18) break;
if(ispr(tp)) st.insert(tp*tp);
tp++;
}
while(*(st.begin())<=n) st.erase(st.begin());
for(int i=1;i<k;i++) st.erase(st.begin());
cout<<*(st.begin());
return 0;
}
标签:Prime,prime,set,power,int,isp,tp,st,init
From: https://www.cnblogs.com/Crazyouth/p/17973255