Soluție HackerRank pentru Megaprime Numbers, subdomeniul Number Theory, în C++14. Include cerința formatată, exemple, explicația pașilor și cod sursă.
- Problemă: Megaprime Numbers
- Domeniu: Number Theory
- Limbaj: C++14
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
Cerință
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 ≤ first ≤ last ≤ 10^15
* last - first ≤ 10^9
Cod sursă
#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;
}
