Super Primes with Prime Decimal Prefixes
National Olympiad — National round (2011 season)
Submission name: super.cpp
Problem summary
Print primes in [a,b] for which repeatedly deleting the final digit leaves primes, except that the final one-digit prefix may also be 1. Number 1 itself is not prime.
Input
a and b.
Output
Qualifying numbers in increasing order, one per line; print NO if none exist.
Constraints
0 < a < b < 10^7.
Worked example
Input and output for the worked example discussed below.
Input
20 50
Output
23 29 31 37
Solution analysis
- Precompute primality up to b using Eratosthenes’ sieve. Start composite marking at p²: smaller multiples of p already have a smaller prime factor.
- For every prime candidate in the interval, divide its prefix by 10 repeatedly. Every prefix of at least two digits must be prime, and the final single digit must be prime or 1. The full number still must be prime, so 1 never qualifies.
- Between 20 and 50, primes 23 and 29 begin with 2, while 31 and 37 begin with 3; all pass. Prime 41 fails because its remaining digit is 4. Prime 11 does qualify through the special final-prefix allowance for 1.
Why it works
The sieve correctly identifies all primes. The prefix loop checks exactly each number obtained by removing one or more rightmost digits, with the specified exception only at the last single digit. Thus a candidate is accepted exactly when it satisfies the definition.
Watch out. Do not accept 1 as a result, and do not reject 11 merely because its last remaining prefix is 1. The interval endpoints are inclusive.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<vector>
using namespace std;
int main(){
int left;
int right;
cin>>left>>right;
vector<bool>prime(right+1,true);
prime[0]=false;
prime[1]=false;
for(int factor=2;factor*factor<=right;factor++){
if(prime[factor]){
for(int multiple=factor*factor;multiple<=right;multiple+=factor){
prime[multiple]=false;
}
}
}
bool found=false;
for(int value=left;value<=right;value++){
if(!prime[value]){
continue;
}
int prefix=value/10;
bool valid=true;
// Only the final one-digit prefix receives the special allowance for 1.
while(prefix>0){
if(!prime[prefix]&&prefix!=1){
valid=false;
}
prefix/=10;
}
if(valid){
found=true;
cout<<value<<'\n';
}
}
if(!found){
cout<<"NO\n";
}
}