0719 - 线性筛+最大质因数 - 数字游戏

3122 数字游戏

描述

Alice和Bob又在玩一个游戏。他们从一个数字X0>=3,开始,期望到很大的数字。游戏是这样的:

Alice先走,然后轮流。在第i个回合中,轮到的玩家找一个小于当前数字的素数,然后选择大于当前数字且是找的素数的倍数的最小数。即选择的素数P < Xi-1,Xi>=Xi-1,Xi是P的倍数,注意如果P是Xi-1的约数,那么数字不会变。

L知道了他们两轮后的状态,现在给你一个X2表示两轮后选择的数字,请你确定最小的起始数字X0。特别提醒,玩家不一定每一步选择是最聪明的,你应该考虑所有可能的情况。

输入

输入一个整数X2,保证X2是合数

输出

输出一个整数X0

样例输入

【输入样例1】
14
【输出样例1】
6
【样例解释】
X0=6,
第一轮:Alice选择素数5,并决定这轮数字X1=10
第一轮:Bob选择素数7,并决定这轮数字X2=14

【输入样例2】
20
【输出样例2】
15
【样例解释】
X0=15,
第一轮:Alice选择素数2,并决定这轮数字X1=16
第一轮:Bob选择素数5,并决定这轮数字X2=20

提示

20%数据 X2<=20

40%数据 X2<=2000

100%数据4<=X2<=1000000


知识储备

  1. 线性筛素数(板子见代码)
  2. 预处理每个数的最大质因数:

记住两条性质

  • 质数的最大质因数为它本身
  • 合数的最大质因数为它最大因数的最大质因数(有点递归的感觉)

而线性筛素数保证了每个合数都是被它的最小质因数所筛去(某数=最小质因数*最大因数),所以可以在线性筛素数的同时处理最大质因数的问题


分析

这道题已知x2求x0,那就倒推回去呗。

已知x2,要去找x1,就得明白x2是如何由x1得到的,然后反推,那么根据题意

找一个小于当前数字(我们现在就指x1)的素数,然后选择大于当前数字(x1)且是找的素数的倍数的最小数

发现x2是 第一个大于x1的 素数p的倍数(这句话有点绕,多读几遍)

也就是说在x1~x2中间没有p的倍数

所以咯,x2-p+1<=x1<=x2       (p为小于x1的一个质数)

又因为要寻找x0的最小,x1应该尽量小,那么p就应该尽量大,则令p为x2的最大质因数

然后找到x1的范围(别忘了x1必须是合数,因为它也是某个质数的倍数),和上面一样,去找x0

具体实现见代码


代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1000009
using namespace std;
int x2,pri[N],p[N],tot=0;
bool vst[N];
void init(){
	int i,j,k;
	for(i=2;i<=N;++i){
		if(!vst[i]) pri[++tot]=i,p[i]=i;
		for(j=1;j<=tot&&pri[j]*i<=N;++j){
			vst[pri[j]*i]=1;
			p[pri[j]*i]=p[i];
			if(i%pri[j]==0) break;
		}
	}
}
int main(){
	scanf("%d",&x2);
	init();//线性筛质数,并求出最大质因数
	int i,j,k,ans=N;
	for(i=x2-p[x2]+1;i<=x2;++i){//枚举x1
		if(!vst[i]) continue;//满足x1不为质数才继续
		int x0=i-p[i]+1;
		ans=min(ans,x0);
	}
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42557561/article/details/81116257