---
# System prepended metadata

title: Free Contest 130 - PLACE

---



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;
}
```