Challenge: Megaprime Numbers
Subdomeniu: Number Theory (number-theory)
Scor cont: 50.0 / 50
Submission status: Accepted
Submission score: 1.0
Submission ID: 464744070
Limbaj: cpp14
Link challenge: https://www.hackerrank.com/challenges/megaprime-numbers/problem
Cerinta
A [prime](https://en.wikipedia.org/wiki/Prime_number) number is an integer greater than $1$ that has no positive divisors other than $1$ and itself.
We call a number *megaprime* if it is prime and all of its individual digits are prime. For example, $53$ is megaprime because it is prime and all its digits ($5$ and $3$) are prime; however, $35$ is not megaprime because it is not prime (it's divisible by $5$ and $7$), and $13$ is not megaprime because it has a non-prime digit ($1$ is not prime).
Given two long integers, $first$ and $last$, find and print the total number of megaprime numbers in the inclusive range between $first$ and $last$.
Input Format
Two space-separated long integers describing the respective values of $first$ and $last$.
Output Format
Print a long integer denoting the total number of megaprimes in the inclusive interval between $first$ and $last$.
Constraints
* $1 \le first \le last \le 10^{15}$
* $last - first \le 10^{9}$
Cod sursa
#include <bits/stdc++.h>
inline bool hasPrimeDigitsOnly(long long n) {
while (n > 0) {
int d = int(n % 10);
if (d != 2 && d != 3 && d != 5 && d != 7) {
return false;
}
n /= 10;
}
return true;
}
std::vector<int> getPrimesTill(int max) {
assert(max >= 1);
std::vector<int> primes;
std::vector<bool> isPrime(1 + max, true);
isPrime[0] = false;
isPrime[1] = false;
for (int i = 2; i * i <= max; i++) {
if (isPrime[i]) {
for (int j = i * i; j <= max; j += i) {
isPrime[j] = false;
}
}
}
for (int i = 2; i < (int)isPrime.size(); i++) {
if (isPrime[i]) {
primes.push_back(i);
}
}
return primes;
}
const int MAX_ROOT = (int)std::sqrt(1e15);
int countMegaPrimes(long long first, long long last) {
assert(1 <= first && last <= (long long)MAX_ROOT * MAX_ROOT);
if (first > last) {
return 0;
}
static std::vector<int> primes = getPrimesTill(MAX_ROOT);
std::vector<bool> isPrime(last - first + 1, true); // isPrime[i] <-> (i + first) is prime
for (int p : primes) {
long long p2 = 1LL * p * p;
if (p2 > last) {
break;
}
long long from = std::max(1LL * p, (first + p - 1) / p) * p;
assert(from >= first);
int fromShifted = (int)(from - first);
int lastShifted = (int)(last - first);
for (int i = fromShifted; i <= lastShifted; i += p) {
isPrime[i] = false;
}
}
int count = 0;
for (int i = 0; i < (int)isPrime.size(); i++) {
if (isPrime[i] && hasPrimeDigitsOnly(i + first)) {
count++;
}
}
return count;
}
int main() {
long long first, last;
scanf("%lld %lld", &first, &last);
const int CHUNK = 10 * 1000 * 1000;
const int CHUNK_FIRST = 2222222; // 7 digits
const int CHUNK_LAST = 7777777; // 7 digits
const int LAST_BEFORE_CHUNK = 777777; // 6 digits
long long count = 0;
if (last <= LAST_BEFORE_CHUNK) {
count = countMegaPrimes(first, last);
} else {
assert(last > LAST_BEFORE_CHUNK);
if (first <= LAST_BEFORE_CHUNK) {
count = countMegaPrimes(first, LAST_BEFORE_CHUNK);
first = LAST_BEFORE_CHUNK + 1;
}
assert(first <= last);
for (long long partFirst = first / CHUNK * CHUNK + CHUNK_FIRST; partFirst <= last; partFirst += CHUNK) {
if (hasPrimeDigitsOnly(partFirst)) {
long long partLast = partFirst - CHUNK_FIRST + CHUNK_LAST;
count += countMegaPrimes(std::max(first, partFirst), std::min(last, partLast));
}
}
}
printf("%lld", count);
return 0;
}
HackerRank Number Theory – Megaprime Numbers
