【JZOJ3188】找数

description

找出第N个最小素因子是P的正整数。


analysis

  • 首先要知道大于109\sqrt{10^9}109ppp第二个就不成立了,范围缩小了很多

  • 设第nnn个满足条件的数是p⋅xp·xpx,这个可以分类讨论一下

  • xxx比较大时,线筛出[1,109p][1,{10^9\over p}][1,p109]的数的最小质因数,然后扫一遍乘个ppp判断可以知道答案

  • xxx比较小时,需要知道一个东西不想打字

=

  • 后面−1-11那个其实是容斥,就是奇数个的答案都减去偶数个的答案实现这个用暴力

  • 就二分xxx,容斥加暴力求出[1,px][1,px][1,px]最小质因子的个数,然后就可以了

  • 根据数据可以发现x=50x=50x=50左右分类较优


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 15000005
#define MAXM 1000000
#define INF 1000000000
#define ll int
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))

using namespace std;

ll prime[MAXM],s[MAXN];
ll n,p,tot,k;

O3 inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
O3 inline void init()
{
	fo(i,2,MAXN-1)
	{
		if (!s[i])prime[++tot]=i,s[i]=i;
		for (reg j=1;j<=tot && prime[j]*i<MAXN;++j)
		{
			s[prime[j]*i]=prime[j];
			if (i%prime[j]==0)break;
		}
	}
}
O3 inline ll judge(ll x)
{
	ll ans=0;
	fo(i,0,k-1)
	{
		long long temp=1ll;int cnt=0;
		for (reg tot=i,j=1;tot;tot/=2,++j)
		{
			if (tot&1)temp*=prime[j],++cnt;
		}
		ans+=(cnt&1?-1:1)*(x/temp);
	}
	return ans;
}
O3 int main()
{
	//freopen("T2.in","r",stdin);
	n=read(),p=read(),init();
	if (p>=50)
	{
		ll i=1;--n;
		while (i<=INF/p && n)
		{
			if (s[i]>=p)
			{
				--n;if (!n)break;
			}
			++i;
		}
		printf("%d\n",!n?i*p:0ll);
		return 0;
	}
	tot=0;while (prime[tot+1]<p)++tot;
	k=1<<tot;
	ll l=0,r=INF/p,ans=0;
	while (l<=r)
	{
		ll mid=(l+r)>>1;
		judge(mid)>=n?ans=mid,r=mid-1:l=mid+1;
	}
	printf("%d\n",ans*p);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值