赛后题解——真假亚瑟王

C. 真假亚瑟王
题目描述

魔术师梅林在水晶球中预见了莫德雷德的叛逆,她决定在在莫德雷德叛逆之前采取一个有效的策略保护亚瑟王。
具体做法如下:使用魔法将亚瑟王复制成N份,当然,其中只有一个使真的。她认为这样就能有效的保护亚瑟王不被杀死。
为了自己能最终找到亚瑟王,她将所有的亚瑟王按1-N编号,并设定了一个密码数字X。真亚瑟王的编号是最接近N的且不能被2−X中任何一个数整除的数。(即真亚瑟王的编号的约数不再2−X中)。

输入

两个整数X,N,用一个空格隔开。

输出

真亚瑟王的编号。

样例输入

3 6

样例输出

5

样例输入

3 4

样例输出

1

样例输入

5 50

样例输出

49

提示

【数据范围】
对于30%的数据, 2 ≤ X ≤ N ≤ 10 2≤X≤N≤10 2XN10
对于60%的数据, 2 ≤ X ≤ N ≤ 1000 2≤X≤N≤1000 2XN1000
对于80%的数据, 2 ≤ X ≤ N ≤ 1 0 5 2≤X≤N≤10^5 2XN105
对于100%的数据, 2 ≤ X ≤ N ≤ 1 0 9 2≤X≤N≤10^9 2XN109

解决思路:分类讨论

提示:不合法代表一定不是答案,合法代表一定是答案。
已知:对于整数 n n n,小于等于 n n n且距离最近的素数离 n n n不会太远,所以直接暴力枚举,判断素数即可。
第一类 x 2 ≥ n x^2 \ge n x2n
1、因为一个合数肯定有一个小于等于根号的因子,所以小于等于 n n n的所有合数的最小因子必然在区间 [ 2 , x ] [2,x] [2,x]内,因此[ 2 , n ] 2,n] 2,n]的合数不合法。
2、 [ 2 , x ] [2,x] [2,x]的每个数不合法。
综上所述, [ x + 1 , n ] [x+1,n] [x+1,n]的素数可能合法。
暴力判断小于等于 n n n且距离最近的素数(前提是大于等于 x + 1 x+1 x+1或者大于 x x x
若存在素数,输出素数。
若不存在素数,输出 1 1 1(由于 [ 2 , n ] [2,n] [2,n]中没有一个数合法,只剩下数字 1 1 1了)
第二类 x 2 < n x^2 < n x2<n
1、因为一个合数肯定有一个小于等于根号的因子,所以小于等于 x 2 x^2 x2的所有合数的最小因子必然在区间 [ 2 , x ] [2,x] [2,x]内,因此 [ 2 , x 2 ] [2,x^2] [2,x2]的合数不合法,但是 [ x 2 + 1 , n ] [x^2+1,n] [x2+1,n]的合数可能合法。
例如: x = 2 , n = 99 x=2,n=99 x=2n=99时, 99 99 99合法但是是合数。
2、 [ x + 1 , n ] [x+1,n] [x+1,n]的素数可能合法。
综上所述,从 n n n开始往小于 n n n的数开始判断,如果这个数是素数或者它不是 [ 2 , x ] [2,x] [2,x]中任意数的倍数的话,输出这个数即可(直接枚举小于根号的因子判断是否在 [ 2 , x ] [2,x] [2,x]内)

#include<cmath>
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

#define mod 77797
typedef long long ll;
const int N = 2e1 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;

bool judge(int n, int x) {
    
    
	if (n == 1) return true;
	if (n >= 2 && n <= x) return false;

	for (int i = 2; i <= n / i; i++) {
    
    
		if (n % i == 0) {
    
    
			if (i <= x) return false;
		}
	}
	return true;
}
bool isPrime(ll n) {
    
    
	if (n == 1) return false;
	for (int i = 2; i <= n / i; i++) {
    
    
		if (n % i == 0) {
    
    
			return false;
		}
	}
	return true;
}

int main() {
    
    

	ll x, n;
	cin >> x >> n;

	if (x * x >= n) {
    
    
		while (n > x) {
    
    
			if (isPrime(n)) {
    
    
				cout << n << endl;
				return 0;
			}
			n--;
		}
		cout << 1 << endl;
		return 0;
	}
	else {
    
    
		while (n) {
    
    
			if (judge(n, x)) {
    
    
				cout << n << endl;
				return 0;
			}
			n--;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45739057/article/details/113137930