#pragma GCC optimize("O3,unroll-loops")
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// ================= 大數類別 (Base 2^32) =================
struct BigInt {
vector<uint32_t> d;
BigInt() {}
BigInt(unsigned long long v) {
while (v > 0) {
d.push_back(v & 0xFFFFFFFF);
v >>= 32;
}
}
bool is_zero() const { return d.empty(); }
void trim() {
while (!d.empty() && d.back() == 0) d.pop_back();
}
bool is_even() const { return d.empty() || (d[0] & 1) == 0; }
bool is_odd() const { return !d.empty() && (d[0] & 1) != 0; }
int bits() const {
if (d.empty()) return 0;
int res = (d.size() - 1) * 32;
uint32_t top = d.back();
while (top) { res++; top >>= 1; }
return res;
}
bool get_bit(int i) const {
int word = i / 32;
int bit = i % 32;
if (word >= d.size()) return false;
return (d[word] >> bit) & 1;
}
void set_bit(int i, bool val) {
int word = i / 32;
int bit = i % 32;
while (d.size() <= word) d.push_back(0);
if (val) d[word] |= (1u << bit);
else d[word] &= ~(1u << bit);
trim();
}
bool operator==(const BigInt& o) const { return d == o.d; }
bool operator!=(const BigInt& o) const { return d != o.d; }
bool operator<(const BigInt& o) const {
if (d.size() != o.d.size()) return d.size() < o.d.size();
for (int i = (int)d.size() - 1; i >= 0; --i) {
if (d[i] != o.d[i]) return d[i] < o.d[i];
}
return false;
}
bool operator<=(const BigInt& o) const { return !(o < *this); }
bool operator>(const BigInt& o) const { return o < *this; }
bool operator>=(const BigInt& o) const { return !(*this < o); }
BigInt operator+(const BigInt& o) const {
BigInt res;
uint64_t carry = 0;
int n = max(d.size(), o.d.size());
for (int i = 0; i < n || carry; ++i) {
uint64_t sum = carry;
if (i < d.size()) sum += d[i];
if (i < o.d.size()) sum += o.d[i];
res.d.push_back(sum & 0xFFFFFFFF);
carry = sum >> 32;
}
res.trim();
return res;
}
BigInt operator-(const BigInt& o) const {
BigInt res;
int64_t borrow = 0;
for (int i = 0; i < d.size(); ++i) {
int64_t diff = d[i] - borrow;
if (i < o.d.size()) diff -= o.d[i];
if (diff < 0) {
diff += 0x100000000LL;
borrow = 1;
} else {
borrow = 0;
}
res.d.push_back(diff);
}
res.trim();
return res;
}
void shift_left_1() {
if (d.empty()) return;
uint32_t carry = 0;
for (int i = 0; i < d.size(); ++i) {
uint32_t next_carry = d[i] >> 31;
d[i] = (d[i] << 1) | carry;
carry = next_carry;
}
if (carry) d.push_back(carry);
}
void shift_right_1() {
if (d.empty()) return;
uint32_t carry = 0;
for (int i = (int)d.size() - 1; i >= 0; --i) {
uint32_t next_carry = (d[i] & 1) << 31;
d[i] = (d[i] >> 1) | carry;
carry = next_carry;
}
trim();
}
BigInt operator*(const BigInt& o) const {
if (is_zero() || o.is_zero()) return BigInt();
BigInt res;
res.d.assign(d.size() + o.d.size(), 0);
for (size_t i = 0; i < d.size(); ++i) {
uint64_t carry = 0;
for (size_t j = 0; j < o.d.size() || carry; ++j) {
uint64_t cur = res.d[i+j] + d[i] * 1ULL * (j < o.d.size() ? o.d[j] : 0) + carry;
res.d[i+j] = cur & 0xFFFFFFFF;
carry = cur >> 32;
}
}
res.trim();
return res;
}
// 二進位長除法 (僅用於 Barrett 預處理)
friend void divmod(const BigInt& a, const BigInt& b, BigInt& q, BigInt& r) {
q.d.clear(); r.d.clear();
if (a < b) { r = a; return; }
for (int i = a.bits() - 1; i >= 0; --i) {
r.shift_left_1();
if (a.get_bit(i)) {
if (r.d.empty()) r.d.push_back(1);
else r.d[0] |= 1;
}
if (r >= b) {
r = r - b;
q.set_bit(i, true);
}
}
}
long long mod_small(long long b) const {
long long rem = 0;
long long base = (1ULL << 32) % b;
for (int i = (int)d.size() - 1; i >= 0; --i) {
rem = (rem * base + d[i]) % b;
}
return rem;
}
};
// ================= Barrett Reduction =================
struct Barrett {
BigInt N, mu;
int k;
Barrett(BigInt n) : N(n) {
k = N.d.size();
BigInt b2k;
b2k.set_bit(2 * k * 32, true);
BigInt rem;
divmod(b2k, N, mu, rem);
}
BigInt reduce(BigInt A) const {
BigInt q1;
if (A.d.size() > k - 1) q1.d.assign(A.d.begin() + k - 1, A.d.end());
BigInt q2 = q1 * mu;
BigInt q3;
if (q2.d.size() > k + 1) q3.d.assign(q2.d.begin() + k + 1, q2.d.end());
BigInt r1;
int r1_size = min((int)A.d.size(), k + 1);
r1.d.assign(A.d.begin(), A.d.begin() + r1_size);
r1.trim();
BigInt r2 = q3 * N;
int r2_size = min((int)r2.d.size(), k + 1);
r2.d.resize(r2_size);
r2.trim();
BigInt r;
if (r1 >= r2) r = r1 - r2;
else {
BigInt bk1;
bk1.set_bit((k + 1) * 32, true);
r = (r1 + bk1) - r2;
}
while (r >= N) r = r - N;
return r;
}
BigInt mul(const BigInt& a, const BigInt& b) const {
return reduce(a * b);
}
BigInt power(BigInt base, BigInt exp) const {
BigInt res = 1;
base = reduce(base);
for (int i = 0; i < exp.bits(); ++i) {
if (exp.get_bit(i)) res = mul(res, base);
base = mul(base, base);
}
return res;
}
};
// ================= BPSW 演算法 =================
BigInt parse(const string& s) {
BigInt res;
int i = 0;
while (i < s.length()) {
int len = min((int)s.length() - i, 9);
long long val = stoll(s.substr(i, len));
long long multiplier = 1;
for(int j = 0; j < len; ++j) multiplier *= 10;
res = res * BigInt(multiplier) + BigInt(val);
i += len;
}
return res;
}
int jacobi(long long a, const BigInt& n) {
int t = 1;
long long n8 = n.mod_small(8);
if (a < 0) {
a = -a;
if (n8 % 4 == 3) t = -t;
}
long long n_val = n.mod_small(a);
while (a != 0) {
while (a % 2 == 0) {
a /= 2;
if (n8 == 3 || n8 == 5) t = -t;
}
swap(a, n_val);
if (a % 4 == 3 && n_val % 4 == 3) t = -t;
a %= n_val;
}
if (n_val == 1) return t;
return 0;
}
bool is_prime(BigInt n) {
if (n == BigInt(2)) return true;
if (n < BigInt(2) || n.is_even()) return false;
// 1. 小質數試除 (加速過濾)
static const int primes[] = {3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
for (int p : primes) {
if (n == BigInt(p)) return true;
if (n.mod_small(p) == 0) return false;
}
Barrett barrett(n);
// 2. Miller-Rabin (Base 2)
BigInt d = n - BigInt(1);
int s = 0;
while (d.is_even()) {
d.shift_right_1();
s++;
}
BigInt x = barrett.power(BigInt(2), d);
bool mr_pass = false;
if (x == BigInt(1) || x == n - BigInt(1)) {
mr_pass = true;
} else {
for (int i = 1; i < s; i++) {
x = barrett.mul(x, x);
if (x == n - BigInt(1)) {
mr_pass = true;
break;
}
}
}
if (!mr_pass) return false;
// 3. 尋找 Lucas 參數 D (Selfridge 方法)
long long D = 5;
int sign = 1;
while (true) {
long long curD = D * sign;
int j = jacobi(curD, n);
if (j == -1) {
D = curD;
break;
}
if (j == 0) return false;
D += 2;
sign = -sign;
}
// 4. Strong Lucas Test
long long Q = (1 - D) / 4;
BigInt Q_mod = (Q < 0) ? n - BigInt(-Q) : BigInt(Q);
BigInt D_mod = (D < 0) ? n - BigInt(-D) : BigInt(D);
BigInt U = BigInt(1), V = BigInt(1);
BigInt Qk = Q_mod;
auto div2_mod = [&](BigInt A) {
if (A.is_odd()) A = A + n;
A.shift_right_1();
if (A >= n) A = A - n;
return A;
};
BigInt K = n + BigInt(1);
BigInt d_lucas = K;
int s_lucas = 0;
while (d_lucas.is_even()) {
d_lucas.shift_right_1();
s_lucas++;
}
for (int i = d_lucas.bits() - 2; i >= 0; --i) {
BigInt U_new = barrett.mul(U, V);
BigInt V_new = barrett.mul(V, V) - barrett.mul(BigInt(2), Qk);
if (V_new >= n) V_new = V_new + n; // 處理負數
Qk = barrett.mul(Qk, Qk);
U = U_new;
V = V_new;
if (d_lucas.get_bit(i)) {
BigInt DU = barrett.mul(D_mod, U);
U = div2_mod(U + V);
V = div2_mod(DU + V);
Qk = barrett.mul(Qk, Q_mod);
}
}
if (U.is_zero() || V.is_zero()) return true;
for (int r = 1; r < s_lucas; ++r) {
V = barrett.mul(V, V) - barrett.mul(BigInt(2), Qk);
if (V >= n) V = V + n;
Qk = barrett.mul(Qk, Qk);
if (V.is_zero()) return true;
}
return false;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
string s;
while (cin >> s) {
if (is_prime(parse(s))) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
return 0;
}