Reputation: 13843
Problem A number is called lucky if the sum of its digits, as well as the sum of the squares of its digits is a prime number. How many numbers between A and B are lucky?
Input: The first line contains the number of test cases T. Each of the next T lines contains two integers, A and B.
Output: Output T lines, one for each case containing the required answer for the corresponding case.
Constraints:
1 <= T <= 10000
1 <= A <= B <= 10^18Sample Input:
2
1 20
120 130
Sample Output:
4
1
Explanation: For the first case, the lucky numbers are 11, 12, 14, 16. For the second case, the only lucky number is 120.
The problem is quite simple if we use brute force, however the running time is so critical that my program failed most test cases. My current idea is to use dynamic programming by storing the previous sum in a temporary array, so for example:
sum_digits(10) = 1 -> sum_digits(11) = sum_digits(10) + 1
The same idea is applied for sum square but with counter equals to odd numbers. Unfortunately, it still failed 9 of 10 test cases which makes me think there must be a better way to solve it. Any idea would be greatly appreciated.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <cmath>
#include <cassert>
#include <bitset>
using namespace std;
bool prime_table[1540] = {
0, 0, 1, 1, 0, 1, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0
};
unsigned num_digits(long long i) {
return i > 0 ? (long) log10 ((double) i) + 1 : 1;
}
void get_sum_and_sum_square_digits(long long n, int& sum, int& sum_square) {
sum = 0;
sum_square = 0;
int digit;
while (n) {
digit = n % 10;
sum += digit;
sum_square += digit * digit;
n /= 10;
}
}
void init_digits(long long n, long long previous_sum[], const int size = 18) {
int current_no_digits = num_digits(n);
int digit;
for (int i = 0; i < current_no_digits; ++i) {
digit = n % 10;
previous_sum[i] = digit;
n /= 10;
}
for (int i = current_no_digits; i <= size; ++i) {
previous_sum[i] = 0;
}
}
void display_previous(long long previous[]) {
for (int i = 0; i < 18; ++i) {
cout << previous[i] << ",";
}
}
int count_lucky_number(long long A, long long B) {
long long n = A;
long long end = B;
int sum = 0;
int sum_square = 0;
int lucky_counter = 0;
get_sum_and_sum_square_digits(n, sum, sum_square);
long long sum_counter = sum;
long long sum_square_counter = sum_square;
if (prime_table[sum_counter] && prime_table[sum_square_counter]) {
lucky_counter++;
}
long long previous_sum[19] = {1};
init_digits(n, previous_sum);
while (n < end) {
n++;
if (n % 100000000000000000 == 0) {
previous_sum[17]++;
sum_counter = previous_sum[17] + previous_sum[18];
sum_square_counter = previous_sum[17] * previous_sum[17] + previous_sum[18] * previous_sum[18];
previous_sum[16] = 0;
previous_sum[15] = 0;
previous_sum[14] = 0;
previous_sum[13] = 0;
previous_sum[12] = 0;
previous_sum[11] = 0;
previous_sum[10] = 0;
previous_sum[9] = 0;
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 10000000000000000 == 0) {
previous_sum[16]++;
sum_counter = previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[15] = 0;
previous_sum[14] = 0;
previous_sum[13] = 0;
previous_sum[12] = 0;
previous_sum[11] = 0;
previous_sum[10] = 0;
previous_sum[9] = 0;
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 1000000000000000 == 0) {
previous_sum[15]++;
sum_counter = previous_sum[15] + previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[14] = 0;
previous_sum[13] = 0;
previous_sum[12] = 0;
previous_sum[11] = 0;
previous_sum[10] = 0;
previous_sum[9] = 0;
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 100000000000000 == 0) {
previous_sum[14]++;
sum_counter = previous_sum[14] + previous_sum[15] + previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[13] = 0;
previous_sum[12] = 0;
previous_sum[11] = 0;
previous_sum[10] = 0;
previous_sum[9] = 0;
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 10000000000000 == 0) {
previous_sum[13]++;
sum_counter = previous_sum[13] + previous_sum[14] + previous_sum[15] + previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[12] = 0;
previous_sum[11] = 0;
previous_sum[10] = 0;
previous_sum[9] = 0;
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 1000000000000 == 0) {
previous_sum[12]++;
sum_counter = previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] + previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[11] = 0;
previous_sum[10] = 0;
previous_sum[9] = 0;
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 100000000000 == 0) {
previous_sum[11]++;
sum_counter =
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] + previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[10] = 0;
previous_sum[9] = 0;
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 10000000000 == 0) {
previous_sum[10]++;
sum_counter =
previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[9] = 0;
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 1000000000 == 0) {
previous_sum[9]++;
sum_counter =
previous_sum[9] + previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[9] * previous_sum[9] +
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[8] = 0;
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 100000000 == 0) {
previous_sum[8]++;
sum_counter =
previous_sum[8] + previous_sum[9] + previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[8] * previous_sum[8] +
previous_sum[9] * previous_sum[9] +
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[7] = 0;
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 10000000 == 0) {
previous_sum[7]++;
sum_counter =
previous_sum[7] + previous_sum[8] + previous_sum[9] + previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[7] * previous_sum[7] +
previous_sum[8] * previous_sum[8] +
previous_sum[9] * previous_sum[9] +
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[6] = 0;
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 1000000 == 0) {
previous_sum[6]++;
sum_counter =
previous_sum[6] + previous_sum[7] + previous_sum[8] + previous_sum[9] + previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[6] * previous_sum[6] +
previous_sum[7] * previous_sum[7] +
previous_sum[8] * previous_sum[8] +
previous_sum[9] * previous_sum[9] +
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[5] = 0;
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 100000 == 0) {
previous_sum[5]++;
sum_counter = previous_sum[5] + previous_sum[6] + previous_sum[7] + previous_sum[8] + previous_sum[9] + previous_sum[10] + previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] + previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[5] * previous_sum[5] +
previous_sum[6] * previous_sum[6] +
previous_sum[7] * previous_sum[7] +
previous_sum[8] * previous_sum[8] +
previous_sum[9] * previous_sum[9] +
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[4] = 0;
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 10000 == 0) {
previous_sum[4]++;
sum_counter =
previous_sum[4] + previous_sum[5] +
previous_sum[6] + previous_sum[7] + previous_sum[8] + previous_sum[9] + previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[4] * previous_sum[4] +
previous_sum[5] * previous_sum[5] +
previous_sum[6] * previous_sum[6] +
previous_sum[7] * previous_sum[7] +
previous_sum[8] * previous_sum[8] +
previous_sum[9] * previous_sum[9] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[3] = 0;
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 1000 == 0) {
previous_sum[3]++;
sum_counter =
previous_sum[3] + previous_sum[4] + previous_sum[5] +
previous_sum[6] + previous_sum[7] + previous_sum[8] + previous_sum[9] + previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[3] * previous_sum[3] +
previous_sum[4] * previous_sum[4] +
previous_sum[5] * previous_sum[5] +
previous_sum[6] * previous_sum[6] +
previous_sum[7] * previous_sum[7] +
previous_sum[8] * previous_sum[8] +
previous_sum[9] * previous_sum[9] +
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[2] = 0;
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 100 == 0) {
previous_sum[2]++;
sum_counter =
previous_sum[2] + previous_sum[3] + previous_sum[4] + previous_sum[5] +
previous_sum[6] + previous_sum[7] + previous_sum[8] + previous_sum[9] + previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[2] * previous_sum[2] +
previous_sum[3] * previous_sum[3] +
previous_sum[4] * previous_sum[4] +
previous_sum[5] * previous_sum[5] +
previous_sum[6] * previous_sum[6] +
previous_sum[7] * previous_sum[7] +
previous_sum[8] * previous_sum[8] +
previous_sum[9] * previous_sum[9] +
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[1] = 0;
previous_sum[0] = 0;
}
else if (n % 10 == 0) {
previous_sum[1]++;
sum_counter =
previous_sum[1] + previous_sum[2] + previous_sum[3] + previous_sum[4] + previous_sum[5] +
previous_sum[6] + previous_sum[7] + previous_sum[8] + previous_sum[9] + previous_sum[10] +
previous_sum[11] + previous_sum[12] + previous_sum[13] + previous_sum[14] + previous_sum[15] +
previous_sum[16] + previous_sum[17] + previous_sum[18];
sum_square_counter =
previous_sum[1] * previous_sum[1] +
previous_sum[2] * previous_sum[2] +
previous_sum[3] * previous_sum[3] +
previous_sum[4] * previous_sum[4] +
previous_sum[5] * previous_sum[5] +
previous_sum[6] * previous_sum[6] +
previous_sum[7] * previous_sum[7] +
previous_sum[8] * previous_sum[8] +
previous_sum[9] * previous_sum[9] +
previous_sum[10] * previous_sum[10] +
previous_sum[11] * previous_sum[11] +
previous_sum[12] * previous_sum[12] +
previous_sum[13] * previous_sum[13] +
previous_sum[14] * previous_sum[14] +
previous_sum[15] * previous_sum[15] +
previous_sum[16] * previous_sum[16] +
previous_sum[17] * previous_sum[17] +
previous_sum[18] * previous_sum[18];
previous_sum[0] = 0;
}
else {
sum_counter++;
sum_square_counter += ((n - 1) % 10) * 2 + 1;
}
// get_sum_and_sum_square_digits(n, sum, sum_square);
// assert(sum == sum_counter && sum_square == sum_square_counter);
if (prime_table[sum_counter] && prime_table[sum_square_counter]) {
lucky_counter++;
}
}
return lucky_counter;
}
void inout_lucky_numbers() {
int n;
cin >> n;
long long a;
long long b;
while (n--) {
cin >> a >> b;
cout << count_lucky_number(a, b) << endl;
}
}
int main() {
inout_lucky_numbers();
return 0;
}
Upvotes: 4
Views: 1277
Reputation: 876
Seeing as A-B may be a range of 10^18 values, there's no way you can loop from A to B in time, no matter how optimized it gets. Let's try to figure out a way to do it that doesn't involve specifically considering all of those numbers...
First, let's reduce the problem to finding the lucky numbers between 1 and E, and call this lucky(E). The answer to the overall problem is simply lucky(B)-lucky(A-1).
Now let's construct such a lucky number digit by digit. Suppose we have already placed a few digits on this number and need to continue. Does it matter which digits we have already placed? No! We only need to know the following:
This will be what is called in dynamic programming as our state.
Let's disregard 10^18, as it's the only number in the input with 19 digits and it's not lucky. Note that E may have up to 18 digits, so we have 19 possibilities for n (from 0 to 18), 162 (18 * 9 + 1) possibilities for s, and 1459 (18 * 81 + 1) possibilities for sq. This leaves us with a search space of at most 5 million, which is incredibly smaller than searching 10^18 numbers for matches.
So let's define F(n, s, sq) as "in how many ways we can add digits to a number that has such properties to get a lucky number" (thanks to kilotaras for the rewording). The base case is when n equals the number of digits in E: F(N, s, s_sq) is 1 if s and sq are prime, 0 otherwise. For the other possibilities, do the possible transitions and call F recursively, taking care not to let the number you're constructing go over E.
In this manner, we can define lucky(E) as F(0, 0, 0).
When you're done, remember to memoize the function for the already calculated inputs/outputs.
Edit: This is a bit old, but here is a sample implementation of the lucky function, which I believe is correct. Note that n goes down in the code as opposed to the explanation above, as it's a lot easier to code it this way.
long long dp[20][163][1460];
bool calc[20][163][1460];
int digits[20];
int digit_cnt;
// The last argument (eq) is used to avoid going over E
long long F(int n, int s, int sq, bool eq) {
// Base cases
if (!eq && calc[n][s][sq]) return dp[n][s][sq];
if (n == 0) return (prime_table[s] && prime_table[sq]);
long long resp = 0;
// Test all possibilities for the next digit
for (int d = 0; d < 10; d++) {
if (!eq || digits[n-1] > d) {
resp += F(n-1, s+d, sq + d*d, false);
}
// If the number formed so far is exactly equal to E
// we will go over E if we pick a larger
// digit than digits[n-1].
// So we have to take care if eq == true
else if (digits[n-1] == d) {
resp += F(n-1, s+d, sq + d*d, true);
}
else break;
}
// Note that computations that have eq set to true
// can't be used in other calculations of F(), as they depend on E.
if (!eq) {
calc[n][s][sq] = true;
dp[n][s][sq] = resp;
}
return resp;
}
long long lucky(long long E) {
long long tE = E;
digit_cnt = 0;
while (tE) {
digits[digit_cnt++] = tE % 10;
tE /= 10;
}
return F(digit_cnt, 0, 0, true);
}
Upvotes: 7
Reputation: 39013
Checking if a number is prime is very easy, the top number you're ever going to encounter is 1458 (for the number 999,999,999,999,999,999). I guess that's why you have the prime_table
, which is good. So looking up if a specific number is prime can't be any faster. I think you should definitely use the prime_table you have, although it would be better if you calculated it at the start of the program, instead of hard-coding it - less chance of an error.
There are other caches you can create. You need to go over all digits and sum them and their squares. But nobody said you should go over the digits one by one. You can go over 5 digits at once - all you need is two arrays with 1000000 cells, one containing the sum of digits and one containing the sum of squares.
So, you have an array for primes, an array for the sum of digits for all 6-figure numbers, and an array for the sum of squares of digits for all 6-figure numbers. Getting a solution for any 18-digit number is going to be very easy - you have 2 modulu operations, 2 divisions, 4 additions and 7 look-ups. You can't get much faster than this.
Note: Play with the 1000000 figure. 100000 might be faster if your L1 cache is small, although I believe with 1000000 you're still fine - you have about 2MBs of data you keep accessing, that should fit snuggly inside your L1 cache.
Upvotes: 2