【JZOJ3188】找数【数论,数学】

题目大意:

题目链接:https://jzoj.net/senior/#main/show/3188
找出第 N N N个最小素因子是 P P P的正整数。


思路:

sto   XXY   orz \color{red}\texttt{sto\ XXY\ orz} sto XXY orz

sto   XXY   orz \color{blue}\texttt{sto\ XXY\ orz} sto XXY orz

sto   XXY   orz \color{green}\texttt{sto\ XXY\ orz} sto XXY orz

sto   XXY   orz(再加一遍XD) \color{white}\texttt{sto\ XXY\ orz(再加一遍XD)} sto XXY orz(再加一遍XD

重要的事情说三遍。


这道题 n ≤ 1 0 9 n\leq 10^9 n109
XXY d a l a o dalao dalao给出了 1 10 \frac{1}{10} 101常数的暴力。
然后就过了。
首先特判 n = 1 n=1 n=1,显然输出1。
然后特判 n > 1 n>1 n>1 p 2 > 1 0 9 p^2>10^9 p2>109,显然输出0。
接下来依次特判 p = 2 , p = 3 , p = 5 , p = 7 , p = 11 p=2,p=3,p=5,p=7,p=11 p=2,p=3,p=5,p=7,p=11。最坏情况下 p = 5 p=5 p=5 1 0 9 2 p \frac{10^9}{2p} 2p109的复杂度。
然后剩下的就是 p > 11 p>11 p>11的了。枚举 p p p的倍数,判断是否成立。
时间复杂度 O ( 1 0 8 + O(10^8+ O(108+某些常数 ) ) )。鉴于JZOJ评测机很好, 416 m s 416ms 416ms跑过了。


代码:

#include <cstdio>
#define rr register
using namespace std;
typedef long long ll;

const int MAXN=1e9;
const int Psum=35000;
int n,p,cnt,k,prime[Psum],v[Psum];
void find(int maxn)
{
	for (int i=2;i<=maxn;i++)
	{
		if (!v[i])
		{
			v[i]=i;
			prime[++cnt]=i;
		}
		for (int j=1;j<=cnt;j++)
		{
			if (prime[j]*i>maxn) break;
			if (prime[j]>v[i]) break;
			v[i*prime[j]]=prime[j];
		}
	}
}

int check(int x)
{
	for (int i=1;i<k;i++)
		if (!(x%prime[i])) return 0;
	return 1;
}

int main()
{
	scanf("%d%d",&n,&p);
	if (n==1)
	{
		printf("%d",p);
		return 0;
	}
	if (n>1&&(ll)p*(ll)p>MAXN)
	{
		printf("0");
		return 0;
	}
	if (p==2)
	{
		if (n*p<=MAXN) printf("%d",n*p);
			else printf("0");
		return 0;
	}
	if (p==3)
	{
		ll x=3+(ll)(n-1)*6;
		if (x<=MAXN) printf("%lld",x);
			else printf("0");
		return 0;
	}
	if (p==5)
	{
		for (rr int i=p;i<=MAXN;i+=2*p)
			if (i%3)
			{
				n--;
				if (!n)
				{
					printf("%d",i);
					return 0;
				}
			}
		printf("0");
		return 0;
	}
	if (p==7)
	{
		for (rr int i=p;i<=MAXN;i+=2*p)
			if (i%3&&i%5)
			{
				n--;
				if (!n)
				{
					printf("%d",i);
					return 0;
				}
			}
		printf("0");
		return 0;
	}
	if (p==11)
	{
		for (rr int i=p;i<=MAXN;i+=2*p)
			if (i%3&&i%5&&i%7)
			{
				n--;
				if (!n)
				{
					printf("%d",i);
					return 0;
				}
			}
		printf("0");
		return 0;
	}
	find(Psum);
	for (k=1;k<=cnt;k++)
		if (prime[k]==p) break;
	for (rr int i=p;i<=MAXN;i+=2*p)
		if (check(i))
		{
			n--;
			if (!n)
			{
				printf("%d",i);
				return 0;
			}
		}
	printf("0");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值