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

Get Node Value

This challenge is part of a tutorial track by MyCodeSchool Given a pointer to the head of a linked list and a specific position, determine the data value at that position. Count backwards from the tail node. The tail is at postion 0, its parent is at 1 and so on. Example head refers to 3 -> 2 -> 1 -> 0 -> NULL positionFromTail = 2 Each of the data values matches its distance from the t

View Solution →

Delete duplicate-value nodes from a sorted linked list

This challenge is part of a tutorial track by MyCodeSchool You are given the pointer to the head node of a sorted linked list, where the data in the nodes is in ascending order. Delete nodes and return a sorted list with each distinct value in the original list. The given head pointer may be null indicating that the list is empty. Example head refers to the first node in the list 1 -> 2 -

View Solution →

Cycle Detection

A linked list is said to contain a cycle if any node is visited more than once while traversing the list. Given a pointer to the head of a linked list, determine if it contains a cycle. If it does, return 1. Otherwise, return 0. Example head refers 1 -> 2 -> 3 -> NUL The numbers shown are the node numbers, not their data values. There is no cycle in this list so return 0. head refer

View Solution →

Find Merge Point of Two Lists

This challenge is part of a tutorial track by MyCodeSchool Given pointers to the head nodes of 2 linked lists that merge together at some point, find the node where the two lists merge. The merge point is where both lists point to the same node, i.e. they reference the same memory location. It is guaranteed that the two head nodes will be different, and neither will be NULL. If the lists share

View Solution →

Inserting a Node Into a Sorted Doubly Linked List

Given a reference to the head of a doubly-linked list and an integer ,data , create a new DoublyLinkedListNode object having data value data and insert it at the proper location to maintain the sort. Example head refers to the list 1 <-> 2 <-> 4 - > NULL. data = 3 Return a reference to the new list: 1 <-> 2 <-> 4 - > NULL , Function Description Complete the sortedInsert function

View Solution →

Reverse a doubly linked list

This challenge is part of a tutorial track by MyCodeSchool Given the pointer to the head node of a doubly linked list, reverse the order of the nodes in place. That is, change the next and prev pointers of the nodes so that the direction of the list is reversed. Return a reference to the head node of the reversed list. Note: The head node might be NULL to indicate that the list is empty.

View Solution →