Free Contest 130 - PLACE
===
[https://oj.vnoi.info/problem/fc130_place](https://oj.vnoi.info/problem/fc130_place)
-----
### Gợi ý:
- Khoảng cách lớn nhất giữa $2$ số nguyên tố liên tiếp không quá $10^9$ là $g = 282$
----
### Hướng dẫn
Xét tập $S = \{2, 3, \dots, B\}$ và $T = \{B + 1, B + 2, \dots, A\}$$
Mình cần tìm số $x \in T$ lớn nhất sao cho $\nexists\ d \in S$ mà $d\ |\ x$
**Nhận xét 1:** Mọi số nguyên tố $p > B$ đều không có ước trong tập $S$ nên nếu có số nguyên tố trong tập $T$ thì chắc chắn có kết quả. Mà vì khoảng cách $d$ lớn nhất giữa $2$ số $p, q$ không có ước thuộc tập $S$ không thể lớn hơn khoảng cách của $2$ số nguyên tố trong đoạn [B + 1, A]. Mà ta có $A \leq 10^9$ nên $d \leq g = 282$
**Nhận xét 2:** Mọi số nguyên thuộc $y$ thỏa $(\frac{x}{2} < y < x)$ đều không phải là ước của $x$. Nên ta chỉ cần duyệt qua các số $d \leq min(B, \sqrt{A})$
$\Rightarrow$ Từ $2$ nhận xét trên, ta có số trường hợp mình cần thử là $O(g \times min(B, \sqrt{A}))$. Đủ để qua được bài này
---
**Có thể tối ưu thêm:**
- Hiển nhiên $x$ là số lẻ vì số chẵn chia hết cho $2$ nên mình chỉ cần kiểm tra số lẻ. Điều này giảm số số phải kiểm tra đi $2$ lần. Ta có thể làm thêm với một số ít số nguyên tố tiếp theo để giảm thêm số số phải kiểm tra, nhưng cải thiện không đáng kể.
- Nếu $d\ |\ x$ thì mọi số nguyên tố $p\ |\ d$ đều thỏa $p\ |\ x$ nên mình chỉ cần kiểm tra qua các số nguyên tố. Và số lượng số nguyên tố không quá $n$ là $O(\pi(n)) \approx O(\frac{n}{\ln n})$
- Ta cũng có thể dùng các thuật toán để phân tích thừa số nguyên tố như Pollard-rho để kiểm tra xem nếu $x$ có ước thuộc tập $\{2, 3, \dots, B\}$ hay không.
-----
### Simple Code
> For constant $g = 282$ is maximal gap of consecutive prime below $10^9$
> **Time:** $O(g \times min(B, \sqrt{A}))$
> **Space:** $O(1)$
> **Algo:** Brute-forces, Math
>
```cpp=
#include <iostream>
using namespace std;
bool check(int b, int a)
{
for (int d = 2; d <= b && d * d <= a; ++d)
if (a % d == 0)
return false;
return true;
}
int main()
{
int b, a;
cin >> b >> a;
while (b < a && !check(b, a)) --a;
cout << (a <= b ? -1 : a);
return 0;
}
```
-----
### Optimized Code
> For $C = min(B, \sqrt{A})$
> For function $\pi(n) =$ number of primes not greater than $n$
> For constant $g = 282$ is maximal gap of consecutive prime below $10^9$
> **Time:** $O \left (g \times \pi(C) \right ) \approx O \left(g \times \frac{\sqrt{A}}{ln(\sqrt{A})} \right)$
> **Space:** $O \left(\pi(C)\right)$
> **Algo:** Sieving, Math
```cpp=
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
/// SPyofgame Linear Sieve
vector<int> prime;
vector<int> lpf;
void sieve(int n)
{
prime.assign(1, 2);
lpf.assign(n + 1, 2);
for (int x = 3; x <= n; x += 2)
{
if (lpf[x] == 2) prime.push_back(lpf[x] = x);
for (int i = 0; i < prime.size() && prime[i] <= lpf[x] && prime[i] * x <= n; ++i)
lpf[prime[i] * lpf[x]] = prime[i];
}
}
const int g = 282;
bool check(int b, int a)
{
for (int p : prime)
{
if (p > b) return true; /// Not found any number in [2, b] is a divisor of (a)
if (a % p == 0) return false; /// Exist a number in [2, b] is a divisor of (a)
}
return true;
}
int main()
{
/// Input
int b, a;
cin >> b >> a;
if (b >= a) /// There is no answer
{
cout << -1;
return 0;
}
sieve(min(b, int(sqrt(a))));
if (a % 2 == 0) --a; /// 2 is a divisor of (a)
while (b < a && !check(b, a)) a -= 2; /// Only care for odd (a)
cout << (a <= b ? -1 : a);
return 0;
}
```