LGP2291题解

。。。去 darkbzoj 上面评测,评测机老是抽风给我 TLE。。。

好在如果寄了会读取上一次的结果,但是如果有人又交了一发就全部木大了/fn

尝试用一个极其奇怪的算法草过去

首先知道答案是 \(p^q\) 的形式,我们枚举这个 \(q\)。当 \(q=2\) 时一定能在 ll 范围内搜出解,所以可以知道 \(q\leq 64\),而且当 \(q\) 过大时可选的值也很少。

考虑 \(q=2\),是最麻烦的一部分。考虑在 \(\sqrt{n}\) 附近确定一段区间,这段区间中有恰好 \(k\) 个质数。

我们知道素数密度是 \(O(\ln n)\),所以这个区间的长度一定是 \(O(k\ln n)\) 级别的。长度可以用 min25 筛+二分找出来。大概在 2e6 级别。

现在的问题就是求出一个 2e6 的区间中有哪些数是质数。区间筛直接莽即可。

\(q=3\) 时,值域缩小到了 \(10^6\),可以直接暴力筛出 \(2\times 10^6\) 中的素数然后暴力判断。

复杂度?\(18\) 以内除去 \(2,3\) 只有 \(5\) 个素数,实际上当 \(q=5\) 时,时间的影响就已经远不如 \(q=2\) 了。

复杂度是 \(O(k\log n\log\log n+\sqrt[4]{n}+\sqrt[3]{n})\)

最后我们会得到 \(O(k)\) 个数,要在这里面寻找第 \(k\) 大的数很容易。

看上去很怪?实际上应该是比较稳的。

如果还觉得不稳的话,可以将 \(q\geq 5\) 时的数打表出来。

fun fact:\(q=2\) 时需要最多需要做 \([10^9,1002075103]\),而 \(1002075101\)\(1002075103\) 恰好是一对孪生素数。

别问怎么找出来的,对着 LOJ6235 代码手动二分的

打表代码:

#include<algorithm>
#include<cstdio>
typedef __int128 LL;
typedef long long ll;
int top,pri[10005],pos[10005];ll len,p[1000005];
inline LL pow(int a,int b){
	LL ans(1);while(b--)ans*=a;return ans;
}
signed main(){
	freopen("ans.out","w",stdout);
	pos[1]=114514;
	for(int i=2;i<=10000;++i){
		if(!pos[i])pri[pos[i]=++top]=i;
		for(int x,j=1;j<=pos[i]&&(x=i*pri[j])<=10000;++j)pos[x]=j;
	}
	for(int i=1;i<=top;++i)pos[pri[i]]=0;
	for(int i=5;i<64;++i)if(!pos[i]){
		int lim=1;while(pow(lim,i)<=1002075103ll*1002075103ll)++lim;--lim;
//		printf("{%d,%d}\n",i,lim);
		for(int j=1;j<=lim;++j)if(!pos[j])p[++len]=pow(j,i);
	}
	std::sort(p+1,p+len+1);
	printf("%d\n",len);
	for(int i=1;i<=len;++i)printf("%lld,",p[i]);
}

代码(表太长了):

#include<cstdio>
typedef unsigned ui;
typedef unsigned long long ull;
const ull p3[669]={};
const ui M=2157415+5,N=2100000;//1002075103
ui top,pri[M],pos[M];bool zhi[N+5];
ull n;ui k;ull p1[M],p2[M];
inline void sieve(const ui&M){
	pos[1]=114514;
	for(ui i=2;i<=M;++i){
		if(!pos[i])pri[pos[i]=++top]=i;
		for(ui x,j=1;j<=pos[i]&&(x=i*pri[j])<=M;++j)pos[x]=j;
	}
	for(int i=1;i<=top;++i)pos[pri[i]]=0;
}
inline ui Sieve(const ui&L,const ui&R){
	ui len(0);if(L==1)zhi[0]=true;
	for(ui i=1;pri[i]*pri[i]<=R;++i){
		const ui&s=(L-1)/pri[i]+1,&t=R/pri[i];
		for(ui j=s;j<=t;++j)zhi[j*pri[i]-L]=true;
	}
	for(ui i=0;i<=R-L+1;++i){
		if(!zhi[i]||(L+i<=2000000&&!pos[L+i]))p1[++len]=1ll*(L+i)*(L+i);if(len==k)return len;
	}
	return len;
}
inline ui sqr(ull n){
	ui L(1),R(1000000000),mid,ans(1);
	while(L<=R)mid=L+R>>1,1ll*mid*mid<=n?ans=mid,L=mid+1:R=mid-1;
	return 1ll*ans*ans==n?ans:ans+1;
}
signed main(){
	ui l1(0),l2(0),l3(0),t1(1),t2(1),t3(1);scanf("%llu%u",&n,&k);++n;
	sieve(2157415);l1=Sieve(sqr(n),sqr(n)+21*(k>=10?k:10));l3=668;
	for(int i=1;i<=top;++i)if(1ull*pri[i]*pri[i]*pri[i]>=n&&l2<k&&1ull*pri[i]*pri[i]*pri[i]<=p1[l1])p2[++l2]=1ull*pri[i]*pri[i]*pri[i];
	while(t3!=l3+1&&p3[t3]<n)++t3;
	for(ui i=1;i<=k;++i){
		ui id(0);ull V(0);
		if(!id||(t1!=l1+1&&p1[t1]<V))id=1,V=p1[t1];
		if(!id||(t2!=l2+1&&p2[t2]<V))id=2,V=p2[t2];
		if(!id||(t3!=l3+1&&p3[t3]<V))id=3,V=p3[t3];
		if(i==k)return printf("%llu",V),0;if(id==1)++t1;if(id==2)++t2;if(id==3)++t3;
	}
}
posted @ 2022-04-01 08:40  Prean  阅读(26)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};