Lucky Numbers


Problem Statement :


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 inclusive, are lucky?

For example, a=20 and b=25. Each number is tested below:

        digit   digit   squares
value   sum     squares sum 
20      2       4,0     4
21      3       4,1     5
22      4       4,4     8
23      5       4,9     13
24      6       4,16    20
25      7       4,25    29
We see that two numbers, 21, 23 and 25 are lucky.

Note: These lucky numbers are not to be confused with Lucky Numbers

Function Description

Complete the luckyNumbers function in the editor below. It should return an integer that represents the number of lucky numbers in the given range.

luckyNumbers has the following parameter(s):

a: an integer, the lower range bound
b: an integer, the higher range bound
Input Format

The first line contains the number of test cases T.
Each of the next T lines contains two space-separated integers, a and b.

Constraints
1 <= T <= 10^4
1 <= a <= b <= 10^18

Output Format

Output T lines, one for each test case in the order given.



Solution :



title-img


                            Solution in C :

In C++ :





#include <iostream>
#include <cstring>

using namespace std;

typedef long long s64;

const int D = 18;
const int MD = 9;
const s64 MAX = 1000000000000000000ull;

s64 dp[D][D*MD+1][D*MD*MD+1];
int hi[D];
bool isPrime[D*MD*MD+1];

s64 go(int idx, int sd, int ssd, bool limited) {
  if (idx == D) return isPrime[sd] && isPrime[ssd] ? 1 : 0;

  s64& ret = dp[idx][sd][ssd];
  if (!limited && ret >= 0) return ret;

  int upper = (limited ? hi[idx] : 9);
  s64 r = 0;
  for (int i = 0; i <= upper; i++)
    r += go(idx+1, sd+i, ssd+i*i, (limited && i == upper));
  if (!limited) ret = r;
  return r;
}

s64 go(s64 n) {
  if (n == MAX) return go(MAX-1);
  if (n <= 1) return 0;
  for (int i = D-1; i >= 0; i--) hi[i] = (int)(n % 10), n /= 10;
  return go(0, 0, 0, true);
}

int main() {
  for (int i = 2; i <= D*MD*MD; i++) isPrime[i] = true;
  for (int i = 2; i <= D*MD*MD; i++)
    if (isPrime[i]) for (int j = i+i; j <= D*MD*MD; j += i) isPrime[j] = false;

  memset(dp, 0xff, sizeof(dp));
  int t; cin >> t;
  while (t--) {
    s64 a, b; cin >> a >> b;
    cout << (go(b)-go(a-1)) << endl;
  }

  return 0;
}









In Java :





import java.io.*;
import java.util.Arrays;

/**
 * @author Sergey Vorobyev (svorobyev@spb.com)
 */
public class Solution {

    MyTokenizer in;
    PrintWriter out;

    public static void main(String[] args) throws Exception {
        Solution instance = new Solution();
        instance.go();
    }

    static class MyTokenizer {
        private BufferedReader in;
        private String[] buffer = new String[]{};
        private int uk;

        MyTokenizer() {
            in = new BufferedReader(new InputStreamReader(System.in));
            
        }

        private String nextToken() throws IOException {
            while (true) {
                if (uk < buffer.length && !buffer[uk].isEmpty()) {
                    return buffer[uk++];
                }
                if (uk >= buffer.length) {
                    uk = 0;
                    buffer = in.readLine().split(" ");
                } else if (buffer[uk].isEmpty()) {
                    uk++;
                }
            }
        }

        int ni() throws IOException {
            return Integer.parseInt(nextToken());
        }

        long nl() throws IOException {
            return Long.parseLong(nextToken());
        }

    }

    private int ni() throws IOException {
        return in.ni();
    }

    private long nl() throws IOException {
        return in.nl();
    }

    boolean[] isPrime;
    long[] fact;
    long[][][] d;
    long[][][] d2;
    long[][][][] bufferedD;
    int[] primes;
    int[] nextPrime;
    int primesCount;

    static final int MAX_DIGITS = 18;
    static final int MAX_SQ_SUM = 81 * MAX_DIGITS + 1;
    static final int MAX_PRIME = 3000;
    static final int MAX_SUM = 9 * MAX_DIGITS + 1;

    void fillPrime() {
        primes = new int[MAX_PRIME];
        nextPrime = new int[MAX_PRIME];
        isPrime = new boolean[MAX_PRIME];
        Arrays.fill(isPrime, true);
        isPrime[0] = isPrime[1] = false;
        int predPrime = -1;
        for (int i = 2; i < MAX_PRIME; i++) {
            if (isPrime[i]) {
                for (int ii = predPrime + 1; ii <= i; ii++) {
                    nextPrime[ii] = primesCount;
                }
                predPrime = i;
                primes[primesCount++] = i;
                for (int j = i * i; j < MAX_PRIME; j += i) {
                    isPrime[j] = false;
                }
            }
        }
    }

    void fillD2() {
        d2 = new long[MAX_DIGITS + 1][MAX_SUM][MAX_SQ_SUM];
        for (int dig = 0; dig <= MAX_DIGITS; dig++) {
            for (int sum = 0; sum + dig * 9 < MAX_SUM; sum++) {
                for (int isum = 0; isum <= Math.min(9*dig, MAX_SUM - sum); isum++) {
                    if (isPrime[sum + isum]) {
                        for (int sqSum = 0; sqSum <= dig*81; sqSum++) {
                            d2[dig][sum][sqSum] += d[dig][isum][sqSum];
                        }
                    }
                }
            }
        }
    }

    private void go() throws Exception {
        long time = System.currentTimeMillis();

        in = new MyTokenizer();
        out = new PrintWriter(System.out);

        fillPrime();

        int FAC_MAX = MAX_DIGITS + 1;
        fact = new long[FAC_MAX];
        fact[0] = 1;
        for (int i = 1; i < FAC_MAX; i++) {
            fact[i] = fact[i - 1] * i;
        }

        d = new long[MAX_DIGITS + 1][MAX_SUM][MAX_SQ_SUM];

        int[] counts = new int[10];
        rec(0 /*pos*/, MAX_DIGITS, 0, 0, 1, true);

        fillD2();


        int T = ni();
        for (int cas = 1; cas <= T; cas++) {
            long A = nl();
            long B = nl();
            out.println(getLucky(B) - getLucky(A - 1));
        }
     
        out.close();

    }

    private long getLucky(long x) {
        if (x == 1000000000000000000L) {
            return getLucky(x - 1);
        }
        int n = log10(x);
        int[] digits = toDigits(x, n);

        return calc(digits);
    }

    private void rec(int pos, int remind, int sum, int sqSum, long div, boolean update) {
        int used = MAX_DIGITS - remind;
        if (update) {
            d[used][sum][sqSum] += fact[used] / div;
        }
        if (pos == 10) {
            return;
        }
        int pos2 = pos * pos;
        for (int i = 0; i <= remind; i++) {
            rec(pos + 1, remind - i, sum, sqSum, div * fact[i], i != 0);
            sum += pos;
            sqSum += pos2;
        }
    }

    private int[] toDigits(long x, int n) {
        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            res[n - i - 1] = (int) (x % 10);
            x /= 10;
        }
        return res;
    }

   private long calc(int[] digits) {

        int n = digits.length;
        long res = 0;

        int sum = 0;
        int sumSq = 0;
        for (int i = 0; i < n; i++) {
            int nmi = n - 1 - i;
            int maxprime = 81 * n;
            if (digits[i] < 5) {

                for (int j = 0; j < digits[i]; j++) {
                    sum += j;
                    sumSq += j * j;

                    for (int p2i = nextPrime[sumSq]; primes[p2i] < maxprime; p2i++) {
                        int isumSq = primes[p2i] - sumSq;
                        res += d2[nmi][sum][isumSq];
                    }
                    sum -= j;
                    sumSq -= j * j;
                }
            } else {
                for (int p2i = nextPrime[sumSq]; primes[p2i] < maxprime; p2i++) {
                    int isumSq = primes[p2i] - sumSq;
                    res += d2[n-i][sum][isumSq];
                }

                for (int j = digits[i]; j < 10; j++) {
                    sum += j;
                    sumSq += j * j;

                    for (int p2i = nextPrime[sumSq]; primes[p2i] < maxprime; p2i++) {
                        int isumSq = primes[p2i] - sumSq;
                        res -= d2[nmi][sum][isumSq];
                    }
                    sum -= j;
                    sumSq -= j * j;
                }
            }

            sum += digits[i];
            sumSq += digits[i] * digits[i];

        }

        // inclusive
        res += isPrime[sum] && isPrime[sumSq] ? 1 : 0;

        return res;
    }
    
    private int log10(long x) {
        int res = 0;
        while (x != 0) {
            res++;
            x /= 10;
        }
        return res;
    }
}








In C :





#include <stdio.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include <assert.h>

#define NUMDIGITS 19
#define NUMSIEVE ((NUMDIGITS-1)*9*9)

// Sieve for generating primes
int p[1+NUMSIEVE];

// Lookup table for factorials
unsigned long long factorial[NUMDIGITS+1];

// To store binned integers
int bin[10];

// Stuff for number lists
typedef struct {
    short s;
    short q;
    unsigned long long mult;
} Element;

static Element *lists[NUMDIGITS+1];

unsigned int listlen[NUMDIGITS+1];
unsigned int listidx[NUMDIGITS+1];

unsigned long long table[1+(NUMDIGITS-2)*9][1+(NUMDIGITS-2)*9*9];
static unsigned long long lookup[NUMDIGITS-1][1+(NUMDIGITS-2)*9][1+(NUMDIGITS-2)*9*9];

void make_list_1(int digit, int n, unsigned long long num, short s, short q, int N)
{
    int i;
    Element *e = lists[n] + listidx[n]++;

    e->s = s;
    e->q = q;
    e->mult = factorial[n]/num;

    if (n==N) return;    

    for (i=digit; i<=9; i++) {
        bin[i]++;
        make_list_1(i, n+1, num*bin[i], s+i, q+i*i, N);
        bin[i]--;
    }
}

void pack_list(int n)
{
    int i, j, k, idx;
    int imax=n*9, jmax=n*9*9, kmax=listlen[n];
    Element *e;

    for (i=0; i<=imax; i++)
        for (j=0; j<=jmax; j++)
            table[i][j] = 0;

    
    for (k=0; k<kmax; k++) {
        e = lists[n]+k;
        table[e->s][e->q] += e->mult;
    }

    idx = 0;
    for (i=0; i<=imax; i++) {
        for (j=0; j<=jmax; j++) {
            if (table[i][j]) {
                e = lists[n]+idx++;
                e->s = i;
                e->q = j;
                e->mult = table[i][j];
            }
        }
    }
    listlen[n] = idx;
}

void make_list(int N)
{
    int i;
    make_list_1(0, 0, 1, 0, 0, N);

    for (i=1; i<=N; i++) {
        pack_list(i);
    }
}

unsigned long long num_lucky(int n, int ss, int sq)
{
    int i, imax=listlen[n];
    unsigned long long ires = 0;
 
    if (lookup[n][ss][sq]) return lookup[n][ss][sq];

    for (i=0; i<imax; i++) {
        if (p[sq+lists[n][i].q]&&p[ss+lists[n][i].s]) {
            ires += lists[n][i].mult;
        }
    }

    if (ires)
        lookup[n][ss][sq] = ires;

    return ires;
}

int main()
{
    int T;
    int i, j;
    int nsieve, sqrtnsieve;
    int len, alen, blen;
    char A[NUMDIGITS+1], B[NUMDIGITS+1];
    int a[NUMDIGITS+1], b[NUMDIGITS+1];
    unsigned long long ires;
    int ssl, ssu, sql, squ;

    // Lengths of lists of candidates
    for (i=0; i<=NUMDIGITS; i++) {
        if (i>0)
            listlen[i] = ((i+9)*listlen[i-1])/i;
        else
            listlen[i] = 1;
        lists[i] = (Element *)malloc(listlen[i]*sizeof(Element));
        listidx[i] = 0;
    }

    // Make primes
    nsieve = NUMSIEVE;
    sqrtnsieve = sqrt(nsieve);
    p[1] = 0;
    for (i=2; i<=nsieve; i++)
        p[i] = 1;
    for (i=2; i<=sqrtnsieve; i++)
        if (p[i]==1)
            for (j=i+i; j<=nsieve; j+=i)
                p[j] = 0;

    // Make factorials
    factorial[0] = 1;
    for (i=1; i<=NUMDIGITS; i++)
        factorial[i] = i*factorial[i-1];

    // Create the master lists
    make_list(17);

    scanf("%d", &T);

    while (T--) {

        scanf("%s %s", A, B);
        alen = strlen(A);
        blen = strlen(B);

        if (alen==19) {
            alen = 18;
            for (i=0; i<alen; i++)
                A[i] = '9';
        }
        if (blen==19) {
            blen = 18;
            for (i=0; i<blen; i++)
                B[i] = '9';
        }
        len = blen;

        for (i=0; i<len; i++)
            a[i] = (i<blen-alen)?0:(A[i-(blen-alen)]-'0');
        for (i=0; i<len; i++)
            b[i] = B[i]-'0';

        ires = 0;
        for(i=a[0]; i<=b[0]; i++)
            ires += num_lucky(len-1, i, i*i);
        
        ssl = sql = ssu = squ = 0;
        for (j=1; j<len; j++) {
            ssl += a[j-1];
            sql += a[j-1]*a[j-1];
            for (i=0;i<a[j];i++) {
                ires -= num_lucky(len-j-1, ssl+i, sql+i*i);
            }
            ssu += b[j-1];
            squ += b[j-1]*b[j-1];
            for (i=9;i>b[j];i--) {
                ires -= num_lucky(len-j-1, ssu+i, squ+i*i);
            }
        }

        printf("%llu\n", ires);
    }

    for (i=0; i<=NUMDIGITS; i++)
        if (lists[i]) free(lists[i]);

    return 0;
}








In Python3 :





def lucky(N):
    p = [int(x) for x in str(N)]
    numDigits = len(p)
    total = 0
    curSum = 0
    curSumSq = 0
    while len(p):
        for a in range(p[0]):
            total += resolve(numDigits - 1, curSum + a, curSumSq + a**2)
        numDigits -= 1
        curSum += p[0]
        curSumSq += p[0]**2
        p.pop(0)
    return total

def resolve(n, s, sq):
    if (n,s,sq) in memo:
        return memo[(n,s,sq)]
    if n == 0:
        if s in primes and sq in primes:
            memo[(n,s,sq)] = 1
            return 1
        memo[(n,s,sq)] = 0
        return 0
    c = 0
    for b in range(10):
        c += resolve(n-1, s + b, sq + b**2)
    memo[(n,s,sq)] = c
    return c

memo = {}
primes = set([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999])

for test in range(int(input())):
    [A,B] = [int(x) for x in input().split(' ')]
    print(lucky(B+1)-lucky(A))
                        








View More Similar Problems

Tree: Postorder Traversal

Complete the postorder function in the editor below. It received 1 parameter: a pointer to the root of a binary tree. It must print the values in the tree's postorder traversal as a single line of space-separated values. Input Format Our test code passes the root node of a binary tree to the postorder function. Constraints 1 <= Nodes in the tree <= 500 Output Format Print the

View Solution →

Tree: Inorder Traversal

In this challenge, you are required to implement inorder traversal of a tree. Complete the inorder function in your editor below, which has 1 parameter: a pointer to the root of a binary tree. It must print the values in the tree's inorder traversal as a single line of space-separated values. Input Format Our hidden tester code passes the root node of a binary tree to your $inOrder* func

View Solution →

Tree: Height of a Binary Tree

The height of a binary tree is the number of edges between the tree's root and its furthest leaf. For example, the following binary tree is of height : image Function Description Complete the getHeight or height function in the editor. It must return the height of a binary tree as an integer. getHeight or height has the following parameter(s): root: a reference to the root of a binary

View Solution →

Tree : Top View

Given a pointer to the root of a binary tree, print the top view of the binary tree. The tree as seen from the top the nodes, is called the top view of the tree. For example : 1 \ 2 \ 5 / \ 3 6 \ 4 Top View : 1 -> 2 -> 5 -> 6 Complete the function topView and print the resulting values on a single line separated by space.

View Solution →

Tree: Level Order Traversal

Given a pointer to the root of a binary tree, you need to print the level order traversal of this tree. In level-order traversal, nodes are visited level by level from left to right. Complete the function levelOrder and print the values in a single line separated by a space. For example: 1 \ 2 \ 5 / \ 3 6 \ 4 F

View Solution →

Binary Search Tree : Insertion

You are given a pointer to the root of a binary search tree and values to be inserted into the tree. Insert the values into their appropriate position in the binary search tree and return the root of the updated binary tree. You just have to complete the function. Input Format You are given a function, Node * insert (Node * root ,int data) { } Constraints No. of nodes in the tree <

View Solution →