Project Euler problem 36 states:
The decimal number, 585 = 1001001001 (binary), is palindromic in both bases.
Find the sum of all numbers, less than one million, which are palindromic in base 10 and base 2.
(Please note that the palindromic number, in either base, may not include leading zeros.)
There is already a solution to this on stack overflow, but I want a more efficient solution.
For example, since the palindrome cannot have leading 0's, no even numbers need to be checked, only odd numbers for which the last bit in binary is a 1. This simple observation already speeds up the brute force "check every number in the range" by a factor of 2.
But I would like to be more clever than that. Ideally, I would like an algorithm with running time proportional to the number of numbers in the sum. I don't think it's possible to do better than that. But maybe that is not possible. Could we for example, generate all palindromic decimal numbers less than one million in time proportional to the number of decimal numbers satisfying that property? (I think the answer is yes).
What is the most efficient algorithm to solve this palindrome sum problem? I would like to consider run-times parameterized by N: the size of the range of numbers (in this case 1 million), D: the set of decimal palindromes in the range, and B: the set of binary palindromes in the range. I hope for a run-time that is o(N) + O( |D intersect B| ), or failing that, O(min(|D|, |B|))
Note: The sequences of binary and decimal palindromes are well known.
e.g. binary palindromes < 100: 0, 1, 3, 5, 7, 9, 15, 17, 21, 27, 31, 33, 45, 51, 63, 65, 73, 85, 93, 99
. . .decimal palindromes < 100:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99,
palindromes in both bases: 0, 1, 3, 5, 7, 9, 33, 99
The binary representations of 33 and 99 are 10001 and 1100011 respectively.
The next number which is a palindrome in both is 585 = 1001001001.
The number of palindromes in base b of length 2*k is (b-1)*b^(k-1), as is the number of palindromes of length 2*k-1. So the number of palindromes not exceeding N in any base is O(sqrt(N))¹. So if you generate all palindromes (not exceeding N) in one base and check if they are also palindromes in the other base, you have an O(sqrt(N)*log(N)) algorithm (the log factor comes from the palindrome check). That's o(N), but I don't know yet if it's also O(|D intersect B|).
It's not O(|D intersect B|) :( There are only 32 numbers up to 1010 which are palindromic in both bases. I don't see any pattern that would allow constructing only those.
¹ If N has d digits (in base b), the number of palindromes not exceeding N is between the number of palindromes having at most d-1 digits and the number of palindromes having at most d digits (both limits inclusive). There are (b-1)*b^(k-1) numbers having exactly k digits (in base b), of which (b-1)*b^(floor((k-1)/2))) are palindromes. Summing gives the number of base-b palindromes with at most k digits as either 2*(b^(k/2)-1) (if k is even) or (b-1)*b^((k-1)/2) + 2*(b^((k-1)/2)-1) (if k is odd). Hence, give or take a factor of 2*b, the number of palindromes with at most d digits is b^(d/2). Thus the number of palindromes not exceeding N is roughly N^0.5, with a factor bounded by a multiple of the base considered.
Consider that there are only about 2000 decimal palindromes between 1 and 1000000. From 1 to 999, you can string the number and its reverse together, both with and without duplicating the "middle" digit (the last digit of the left part). For each of those, you check whether it's also a binary palindrome, and if it is, it's part of the sum.
(not an answer to your question but a cute recursive bit-fiddling solution to Project Euler 36)
This may not be the most efficient algorithm but I like how it looks like. I wrote it after reading Daniel Fischer's answer, suggesting to generate all palindromes in one base and then checking in the other base if it's a palindrome too.
In 18 lines of code (including the brackets) it generates all the palindromes in base 2 and then checks if they're also palindrome in base 10.
Takes about 6 ms on my system.
This can probably be optimized (too many bitshifting operation to my taste, there's probably quite some unnecessary junk here) and there may be a better algo, but I "like" (+) the look of my code ; )
#Test
public void testProjectEuler36() {
final int v = rec(1, 1);
assertEquals( 872187, v );
}
public static int rec( final int n, final int z ) {
if ( n > 1000000 )
return 0;
if ( z % 2 == 0 ) {
final int l = n << 1 & -1 << z / 2 + 1;
final int r = n & -1 >>> 32 - z / 2;
return v(n) + rec( l | 1 << z / 2 | r, z + 1 ) + rec( l | r, z + 1 );
} else
return v(n) + rec( n << 1 & -1 << z / 2 + 1 | n & -1 >>> 31 - z / 2, z + 1 );
}
public static int v( final int n ) {
final String s = "" + n;
boolean ok = true;
for ( int j = s.length(), i = j / 2 - 1; i >= 0 && ok; i--)
ok = s.charAt(i) == s.charAt(j-(i+1));
return ok ? n : 0;
}
My first assumptions were entirely wrong, so I've fixed them up. I've provided two algorithms, one iterative and one recursive. They're obviously nowhere near as impressive and efficient as user988052's, but they're definitely easier to read! The first algorithm is iterative and has a runtime of 9ms. The second algorithm is recursive and has a runtime of 16ms. Although the second solution is cleaner, the recursive calls might be slowing it down.
First Algorithm (9ms):
/** Given half a palindrome, construct the rest of the palindrome with
* an optional string inserted in the middle. The returned string is
* only guaranteed to be a palindrome if 'mid' is empty or a palindrome. */
public static String getPalindrome(String bin_part, String mid) {
return bin_part + mid + (new StringBuilder(bin_part)).reverse();
}
/** Check if the specified string is a palindrome. */
public static boolean isPalindrome(String p) {
for (int i=0; i<p.length()/2; i++)
if (p.charAt(i) != p.charAt(p.length()-1-i))
return false;
return true;
}
public static void main(String[] args) {
String[] mids = {"0","1"};
long total = 0;
boolean longDone = false; // have the numbers with extra digits been tested
long start = System.currentTimeMillis();
for (long i=0; i<1000; i++) {
String bin_part = Long.toBinaryString(i);
String bin = getPalindrome(bin_part, "");
long dec = Long.valueOf(bin, 2);
if (dec >= 1000000) break; // totally done
if (isPalindrome(Long.toString(dec)))
total += dec;
if (!longDone) {
for (int m=0; m<mids.length; m++) {
bin = getPalindrome(bin_part, mids[m]);
dec = Long.valueOf(bin, 2);
if (dec >= 1000000) {
longDone = true;
break;
}
if (isPalindrome(Long.toString(dec)))
total += dec;
}
}
}
long end = System.currentTimeMillis();
System.out.println("Total: " + total + " in " + (end-start) + " ms");
}
Second Algorithm (16ms)
public long total = 0;
public long max_value = 1000000;
public long runtime = -1;
public static boolean isPalindrome(String s) {
for (int i=0; i<s.length()/2; i++)
if (s.charAt(i) != s.charAt(s.length()-1-i))
return false;
return true;
}
public void gen(String bin, boolean done) {
if (done) { // generated a valid binary number
// check current value and add to total if possible
long val = Long.valueOf(bin, 2);
if (val >= max_value)
return;
if (isPalindrome(Long.toString(val))) {
total += val;
}
// generate next value
gen('1' + bin + '1', true);
gen('0' + bin + '0', false);
} else { // generated invalid binary number (contains leading and trailing zero)
if (Long.valueOf('1' + bin + '1', 2) < max_value) {
gen('1' + bin + '1', true);
gen('0' + bin + '0', false);
}
}
}
public void start() {
total = 0;
runtime = -1;
long start = System.currentTimeMillis();
gen("",false);
gen("1",true);
gen("0",false);
long end = System.currentTimeMillis();
runtime = end - start;
}
public static void main(String[] args) {
Palindromes2 p = new Palindromes2();
p.start();
System.out.println("Total: " + p.total + " in " + p.runtime + " ms.");
}
Here is the best Python Implementation to solve this problem :
sum = 0
for i in range(1000000):
bina = int(str(bin(i)).replace('0b',''))
if(i==int(str(i)[::-1]))or(bina==int(str(bina)[::-1])):
#print("i : "+str(i))
#print("bina : "+str(bina))
sum+=i
print("Sum of numbers : ",sum)
Related
S is defined to be the set of all positive integers whose binary representation does not have consecutive '1's. Find the lexicographical order, i.e. the number of elements of
S less than or equal to it, of the given number.
e.g.
input: 17
output: 9
Explanation: The 8 numbers in the set smaller than 17 are 1, 2, 4, 5, 8, 9, 10 and 16.
*The input is guaranteed to be in the set S.
My attempt:
If the input is an integer power of 2, then it's just a fibonacci-like dynamic programming problem. However, the idea no longer works if the input is not an integer power of 2. So I am thinking about using inclusion-exclusion but so far I haven't found something that can be run in a reasonable time. Any hints are welcomed.
Zeckendorf's theorem says that:
every positive integer can be represented uniquely as the sum of one or more distinct Fibonacci numbers in such a way that the sum does not include any two consecutive Fibonacci numbers.
This means that as your number 17 is the Zeckendorf representation of 9, there are therefore 8 numbers smaller that are in the set.
Therefore to compute the answer:
Convert number into binary (17d -> 10001b bits set at position 1 and 5)
Add the fibonacci number Fi for each set bit at position i (F5+F1 = 8 + 1 = 9)
Subtract 1 (9 - 1 = 8)
For completeness, here is the digit dynamic program with O(log n) time and O(1) space, including a check against brute force.
JavaScript code:
function bruteForce(n){
let result = 0;
let last;
for (let k=1; k<=n; k++){
let i = k;
let prev;
let valid = 1;
while (i){
bit = i & 1;
if (bit && prev){
valid = 0;
break;
}
prev = bit;
i >>= 1;
}
result += valid;
if (valid)
last = k
}
return last == n ? [last, result] : null;
}
function f(n){
// Counts:
// Bit set and bound
// Bit unset and bound
// Bit set and unbound
// Bit unset and unbound
let dp = [0, 0, 0, 0];
let dp_prev = [0, 1, 0, 1];
let result = 0;
while (n){
const bit = n & 1;
n >>= 1;
// Add only the bound result for
// the most significant bit of n
if (!n){
result += dp_prev[1];
break;
}
if (bit){
dp[0] = dp_prev[1];
dp[1] = dp_prev[2] + dp_prev[3];
} else {
dp[0] = 0;
dp[1] = dp_prev[0] + dp_prev[1];
}
// (Fibonacci)
dp[2] = dp_prev[3];
dp[3] = dp_prev[2] + dp_prev[3];
// Add result for all numbers
// with this bit as most significant
if (n)
result += dp[2];
dp_prev = dp;
dp = [0, 0, 0, 0];
}
return result;
}
for (let n=1; n<2000; n++){
const bf = bruteForce(n);
// n must be a member of S,
// which we check in bruteForce
if (bf){
const _f = f(n);
if (_f != bf[1]){
console.log(`Mismatch: ${ n }, b${ n.toString(2) }, brute force: ${ bf[1] }, f: ${ _f }`);
break;
}
}
}
console.log('Done testing.');
Assume you need n steps (e.g. 100) to visit back to the start point on Monopoly,
how many combination of rolling a die to reach start point again.
The min throw count is round up (n/6), max is n (throwing 1 for n times).
n might be greater than 10000. But I can't think of any better solution other than brute force.
It depends if the order matters or not.
Let's say it doesn't. That is,
throwing 1, 2, 3 is the same as throwing 3, 2, 1. In this case this Scala snippet should work just fine.
def count(n: Int): Int = {
def count(n: Int, dots: List[Int]): Int = dots match {
case _ if n == 0 => 1
case h :: t if n > 0 => count (n - h, h :: t) + count (n, t)
case _ => 0
}
count(n, List(1, 2, 3, 4, 5, 6))
}
If the order matters than this would be the solution.
import java.math.BigInteger;
import java.util.LinkedList;
public class HexabonacciSolver {
public BigInteger solve(int n) {
LinkedList<BigInteger> lastSix = new LinkedList<>();
lastSix.add(new BigInteger("1"));
lastSix.add(new BigInteger("2"));
lastSix.add(new BigInteger("4"));
lastSix.add(new BigInteger("8"));
lastSix.add(new BigInteger("16"));
lastSix.add(new BigInteger("32"));
if (n < 7)
return lastSix.get(n - 1);
for (int i = 0; i < n - 6; i++){
lastSix.add(lastSix.get(0).add(lastSix.get(1).add(lastSix.get(2).add(lastSix.get(3).add(lastSix.get(4).add(lastSix.get(5)))))));
lastSix.removeFirst();
}
return lastSix.get(5);
}
}
Explanation: How does it work?
Let's say you want to know how many different sequences of dice rolls there are to get into the field 100 in Monopoly. You know that to get there the previous rolls had to be either 6, 5, 4, 3, 2 or 1. If you only had the number of different sequences of rolls needed to arrive to the fields 94, 95, 96, 97, 98, 99 you could just sum them up and get the solution for the field 100. This is exactly what the program does. This is very analogous to how the Fibonacci sequence is build with the difference that the next number in the sequence is calculated by summing up 6 previous numbers (hence the name "Hexabonacci")
The solution is linear O(N) in time and constant O(C) in space as we only need to store 6 last numbers of the Hexabonacci sequence.
Since the result for n=10000 has hundreds of digits the Java solution returns a BigInteger.
Let me know if you'd like to see a solution in Scala/Python/JavaScript.
Simple dynamic programming can solve this problem
#include<bits/stdc++.h>
using namespace std;
int n;
int dp[100010] = {0};
int main() {
cin >> n;
dp[0] = dp[1] = 1;
for(int i=2; i<=n ; i++){
for(int j=1; j<=6; j++)
if(i - j >= 0)
dp[i] += dp[i-j];
}
cout << dp[n] << endl;
return 0;
}
Define dp[x] be the total # of the ordered combination to achieve sum x, using 1 to 6 each step,
then dp[x] = sum (dp[x - i]) where 1 <= i <= 6 and x-i >= 0
The base case is dp[0] = dp[1] = 1
One point to note is that the number is growing fast, you may need to use long long / 64bit integer to store the result
For example, to achieve 4 steps in total,
dp(4) = dp(3) + dp(2) + dp(1) + dp(0)
= 4 + 2 + 1 + 1
= 8
Corresponding to [1,2,1], [2,1,1], [1,1,1,1], [3,1], [2,2], [1,1,2], [1,3], [4]
Without using /, % and * operators, write a function to divide a number by 3. itoa() is available.
The above was asked from me in an interview and I couldn't really come up with an answer. I thought of converting the number to a string and adding all the digits, but that will just tell me whether number is divisible or not. Or, by repeated subtraction it can also tell me the remainder. But, how do I obtain the quotient on division?
The below code takes in 2 integers, and divides the first by the second. It supports negative numbers.
int divide (int a, int b) {
if (b == 0)
//throw division by zero error
//isPos is used to check whether the answer is positive or negative
int isPos = 1;
//if the signs are different, the answer will be negative
if ((a < 0 && b > 0) || (a > 0 && b < 0))
int isPos = 0;
a = Math.abs(a);
b = Math.abs(b);
int ans = 0;
while (a >= b) {
a = a-b;
ans++;
}
if (isPos)
return 0-ans;
return ans;
}
According to itoa the number is integer.
int divide(int a, int b)
{
int n=0;
while(1)
{
a-=b;
if(a<b)
{
n=n+1;
return n;
}
else
n=n+1;
}
}
Just count how many times b in a by subtracting it
Edit: Removed the limit
The "count how many times you subtract 3" algorithm takes theta(|input|) steps. You could argue that theta(|input|) is fine for 32-bit integers, in which case why do any programming? Just use a lookup table. However, there are much faster methods which can be used for larger inputs.
You can perform a binary search for the quotient, testing whether a candidate quotient q is too large or too small by comparing q+q+q with the input. Binary search takes theta(log |input|) time.
Binary search uses division by 2, which can be done by the shift operator instead of /, or you can implement this yourself on arrays of bits if the shift operator is too close to division.
It is tempting to use the fact that 1/3 is the sum of the geometric series 1/4 + 1/16 + 1/64 + 1/256 + ... by trying (n>>2) + (n>>4) + (n>>6) + ... however this produces the wrong answer for n=3,6,7,9, 11, 12, 13, 14, 15, 18, ... It is off by two for n=15,30,31, 39, .... In general, this is off by O(log n). For n nonnegative,
(n>>2) + (n>>4) + (n>>6) + ... = (n-wt4(n))/3
where wt4(n) is the sum of the base 4 digits of n, and the / on the right hand side is exact, not integer division. We can compute n/3 by adding wt4(n)/3 to (n>>2)+(n>>4)+(n>>6)+... We can compute the base 4 digits of n and therefore wt4(n) using only addition and the right shift.
int oneThirdOf(int n){
if (0<=n && n<3)
return 0;
if (n==3)
return 1;
return sum(n) + oneThirdOf(wt4(n));
}
// Compute (n>>2) + (n>>4) + (n>>6) + ... recursively.
int sum(int n){
if (n<4)
return 0;
return (n>>2) + sum(n>>2);
}
// Compute the sum of the digits of n base 4 recursively.
int wt4(int n){
if (n<4)
return n;
int fourth = n>>2;
int lastDigit = n-fourth-fourth-fourth-fourth;
return wt4(fourth) + lastDigit;
}
This also takes theta(log input) steps.
I have solved the program here. Previously I thought complexity was O(n!)
where n were characters in the word.
But today I feel it is wrong. It should be (6)^(characters in the word) where 6 is the sides in the cube.
Making it more generic, assuming cube would have more than 6 sides, the complexity should be O(cubefaces ^ (characters in input word))
Can someone please explain me time-complexity in this case?
If there is if (cubeMatrix.length != word.length()) return false;, and every side letter of the cube is unique (i.e. no two sides of a cube have the same letter), then the time complexity of your algorithm is O(SN - S + 1 S!) when N >= S, and O(S N!) when N <= S. Here S is the number of cube sides, and N is the number of cubes.
In brief, you make the recursive call only then there is a unused letter in the word corresponding to the cube side letter, so, in the worst case the number of times you make the recursive call is not more than the number of word letters left unused. And the number of unused word letters decreases with increasing of the recursion depth, and eventually this number becomes less than the number of cube sides. That's why, in the final recursion depths the complexity becomes factorial.
A bit more details
Let's introduce f(n) that is how many times you call findWordExists with cubeNumber = n. We also introduce g(n) that is how many times findWordExists with cubeNumber = n recursively calls itself (but now with cubeNumber = n + 1).
f(0) = 1, because you call findWordExists non-recursively only once.
f(n) = f(n - 1) g(n - 1) when n > 0.
We know that g(n) = min { S, N - n }, because, as I already pointed out, findWordExists is called recursively no more times than the number of letters left — the if (frequency > 0) check is responsible for this — and the number of letters left equals to the number of cubes left, i.e. N - n.
Now we can calculate how many times findWordExists is called in total:
f(0) + f(1) + ... + f(N) =
= 1 + g(0) + g(0) g(1) + ... + g(0) g(1) ... g(N - 1) =
= 1 + S + S2 + ... + SN - S + SN - S (S - 1) + SN - S (S - 1) (S - 2) + ... + SN - S (S - 1) (S - 2) ... 1 =
= O(SN - S S!).
But every findWordExists call (except finals) iterate over each side, so we need to multiply the number of findWordExists calls by the number of sides: S O(SN - S S!) = O(SN - S + 1 S!) — and that is our time complexity.
Better Algorithm
Actually, your problem is a bipartite matching problem, so there are much more efficient algorithms than brute force, e.g. Kuhn’s algorithm.
The complexity of Kuhn’s algorithm is O(N M), where N is the number of vertices, and M is the number of edges. In your case, N is the number of cubes, and M is just N2, so the complexity in your case could be O(N3). But you also need to iterate over all the sides of all the cubes, so if the number of cube sides is greater than N2, then the complexity is O(N S), where S is the number of cube sides.
Here is a possible implementation:
import java.util.*;
public class CubeFind {
private static boolean checkWord(char[][] cubes, String word) {
if (word.length() != cubes.length) {
return false;
}
List<Integer>[] cubeLetters = getCubeLetters(cubes, word);
int countMatched = new BipartiteMatcher().match(cubeLetters, word.length());
return countMatched == word.length();
}
private static List<Integer>[] getCubeLetters(char[][] cubes, String word) {
int cubeCount = cubes.length;
Set<Character>[] cubeLetterSet = new Set[cubeCount];
for (int i = 0; i < cubeCount; i++) {
cubeLetterSet[i] = new HashSet<>();
for (int j = 0; j < cubes[i].length; j++) {
cubeLetterSet[i].add(cubes[i][j]);
}
}
List<Integer>[] cubeLetters = new List[cubeCount];
for (int i = 0; i < cubeCount; i++) {
cubeLetters[i] = new ArrayList<>();
for (int j = 0; j < word.length(); j++) {
if (cubeLetterSet[i].contains(word.charAt(j))) {
cubeLetters[i].add(j);
}
}
}
return cubeLetters;
}
public static void main(String[] args) {
char[][] m = {{'e', 'a', 'l'} , {'x', 'h' , 'y'}, {'p' , 'q', 'l'}, {'l', 'h', 'e'}};
System.out.println("Expected true, Actual: " + CubeFind.checkWord(m, "hell"));
System.out.println("Expected true, Actual: " + CubeFind.checkWord(m, "help"));
System.out.println("Expected false, Actual: " + CubeFind.checkWord(m, "hplp"));
System.out.println("Expected false, Actual: " + CubeFind.checkWord(m, "hplp"));
System.out.println("Expected false, Actual: " + CubeFind.checkWord(m, "helll"));
System.out.println("Expected false, Actual: " + CubeFind.checkWord(m, "hel"));
}
}
class BipartiteMatcher {
private List<Integer>[] cubeLetters;
private int[] letterCube;
private boolean[] used;
int match(List<Integer>[] cubeLetters, int letterCount) {
this.cubeLetters = cubeLetters;
int cubeCount = cubeLetters.length;
int countMatched = 0;
letterCube = new int[letterCount];
Arrays.fill(letterCube, -1);
used = new boolean[cubeCount];
for (int u = 0; u < cubeCount; u++) {
if (dfs(u)) {
countMatched++;
Arrays.fill(used, false);
}
}
return countMatched;
}
boolean dfs(int u) {
if (used[u]) {
return false;
}
used[u] = true;
for (int i = 0; i < cubeLetters[u].size(); i++) {
int v = cubeLetters[u].get(i);
if (letterCube[v] == -1 || dfs(letterCube[v])) {
letterCube[v] = u;
return true;
}
}
return false;
}
}
for (int i = 0; i < cubeMatrix[cubeNumber].length; i++)
This will tell about the number of characters in the given cubes(or rather faces of the cube).
Also, inside this loop, you have a
if (frequency > 0) {
charFreq.put(cubeMatrix[cubeNumber][i], frequency - 1);
if (findWordExists(cubeMatrix, charFreq, cubeNumber + 1)) {
return true;
..
// and so on.
This will result in a recursive call, thereby calling for the cubeNumber+1, then cubeNumber+1+1,.., and so on.
And, at last when this condition
if (cubeNumber == cubeMatrix.length) {
for (Integer frequency : charFreq.values()) {
if (frequency > 0) return false;
}
return true;
}
will meet, the for-loop wont't get executed any further.
Assuming, no. of cubes = n, and the characters stored in each cube = generalised faces of each cube(as coined by OP) = f.
WORST CASE ANALYSIS :-
Starting from 0th cube to (n-1)th cube, the for-loop will iterate for cubeMatrix[cubeNumber].length times, which is equal to the number of characters stored in each cube = f times.
And, in each of the iteration of the for-loop, the actual recursive call in the case of cubeNumber 0 will be n-1 times, till it reaches the last cube number.
Hence, for each character entry in the cubeArray(f characters), we have to call all the cubes available(total n as per our assumption).
Hence, total number of times the code checks for finding a word = f ^ n.
In your terms, f = cubefaces = number of characters possible on the faces of your generalised cube;
and , n = total number of cubes available for your test.
It does depend on the frequency of characters which is reduced based
upon the character in the word when the word length doesn't match with
the number of cubes.In that case, the result will be false.
But, in those case where word length is equal to the number of cubes,
in the worst case, the output will be independent of the word length.
Strictly, it will also depend on the number of characters of the word(as comparison with frequency will reduce several cases in calculation), but, in worst-case scenario, unfortunately, it doesn't depend on the number of characters in the word as we will be checking all the entries of characters in all of the available cubes to create the word.
1<=N<=1000
How to find the minimal positive number, that is divisible by N, and its digit sum should be equal to N.
For example:
N:Result
1:1
10:190
And the algorithm shouldn't take more than 2 seconds.
Any ideas(Pseudocode,pascal,c++ or java) ?
Let f(len, sum, mod) be a bool, meaning we can build a number(maybe with leading zeros), that has length len+1, sum of digits equal to sum and gives mod when diving by n.
Then f(len, sum, mod) = or (f(len-1, sum-i, mod- i*10^len), for i from 0 to 9). Then you can find minimal l, that f(l, n, n) is true. After that just find first digit, then second and so on.
#define FOR(i, a, b) for(int i = a; i < b; ++i)
#define REP(i, N) FOR(i, 0, N)
#define FILL(a,v) memset(a,v,sizeof(a))
const int maxlen = 120;
const int maxn = 1000;
int st[maxlen];
int n;
bool can[maxlen][maxn+1][maxn+1];
bool was[maxlen][maxn+1][maxn+1];
bool f(int l, int s, int m)
{
m = m%n;
if(m<0)
m += n;
if(s == 0)
return (m == 0);
if(s<0)
return false;
if(l<0)
return false;
if(was[l][s][m])
return can[l][s][m];
was[l][s][m] = true;
can[l][s][m] = false;
REP(i,10)
if(f(l-1, s-i, m - st[l]*i))
{
can[l][s][m] = true;
return true;
}
return false;
}
string build(int l, int s, int m)
{
if(l<0)
return "";
m = m%n;
if(m<0)
m += n;
REP(i,10)
if(f(l-1, s-i, m - st[l]*i))
{
return char('0'+i) + build(l-1, s-i, m - st[l]*i);
}
return "";
}
int main(int argc, char** argv)
{
ios_base::sync_with_stdio(false);
cin>>n;
FILL(was, false);
st[0] = 1;
FOR(i, 1, maxlen)
st[i] = (st[i-1]*10)%n;
int l = -1;
REP(i, maxlen)
if(f(i, n, n))
{
cout<<build(i,n,n)<<endl;
break;
}
return 0;
}
NOTE that this uses ~250 mb of memory.
EDIT: I found a test where this solution runs, a bit too long. 999, takes almost 5s.
Update: I understood that the result was supposed to be between 0 and 1000, but no. With larger inputs the naïve algorithm can take a considerable amount of time. The output for 80 would be 29999998880.
You don't need a fancy algorithm. A loop that checks your condition for 1000 numbers will take less than 2 seconds on any reasonably modern computer, even in interpreted languages.
If you want to make it smart, you only need to check numbers that are multiples of N. To further restrict the search space, the remainders of N and the result have to be equal when divided by 9. This means that now you have to check only one number in every 9N.
Sure, pseudo-code, since it smells like homework :-)
def findNum (n):
testnum = n
while testnum <= 1000:
tempnum = testnum
sum = 0
while tempnum > 0:
sum = sum + (tempnum mod 10)
tempnum = int (tempnum / 10)
if sum == n:
return testnum
testnum = testnum + n
return -1
It takes about 15 thousandths of a second when translated to Python so well under your two-second threshold. It works by basically testing every multiple of N less than or equal to 1000.
The test runs through each digit in the number adding it to a sum then, if that sum matches N, it returns the number. If no number qualifies, it returns -1.
As test cases, I used:
n findNum(n) Justification
== ========== =============
1 1 1 = 1 * 1, 1 = 1
10 190 190 = 19 * 10, 10 = 1 + 9 + 0
13 247 247 = 13 * 19, 13 = 2 + 4 + 7
17 476 476 = 17 * 28, 17 = 4 + 7 + 6
99 -1 none needed
Now that only checks multiples up to 1000 as opposed to checking all numbers but checking all numbers starts to take much more than two seconds, no matter what language you use. You may be able to find a faster algorithm but I'd like to suggest something else.
You will probably not find a faster algorithm than what it would take to simply look up the values in a table. So, I would simply run a program once to generate output along the lines of:
int numberDesired[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
190, 209, 48, 247, 266, 195, 448, 476, 198, 874,
...
-1, -1};
and then just plug that into a new program so that it can use a blindingly fast lookup.
For example, you could do that with some Python like:
print "int numberDesired[] = {"
for i in range (0, 10):
s = " /* %4d-%4d */"%(i*10,i*10+9)
for j in range (0, 10):
s = "%s %d,"%(s,findNum(i*10+j))
print s
print "};"
which generates:
int numberDesired[] = {
/* 0- 9 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
/* 10- 19 */ 190, 209, 48, 247, 266, 195, 448, 476, 198, 874,
/* 20- 29 */ 3980, 399, 2398, 1679, 888, 4975, 1898, 999, 7588, 4988,
/* 30- 39 */ 39990, 8959, 17888, 42999, 28798, 57995, 29988, 37999, 59888, 49998,
/* 40- 49 */ 699880, 177899, 88998, 99889, 479996, 499995, 589996, 686999, 699888, 788998,
/* 50- 59 */ 9999950, 889899, 1989988, 2989889, 1999998, 60989995, 7979888, 5899899, 8988898, 8888999,
/* 60- 69 */ 79999980, 9998998, 19999898, 19899999, 59989888, 69999995, 67999998, 58999999, 99899888, 79899999,
:
};
That will take a lot longer than two seconds, but here's the thing: you only have to run it once, then cut and paste the table into your code. Once you have the table, it will most likely blow away any algorithmic solution.
The maximum digit sum you have to worry about is 1000. Since 1000 / 9 = ~100 This is actually not a lot, so I think the following should work:
Consider the following data structure:
entry { int r, sum, prev, lastDigit; }
Hold a queue of entry where initially you have r = 1 mod N, sum = 1, prev = -1, lastDigit = 1; r = 2 mod N, sum = 2, prev = -1, lastDigit = 2 etc.
When you extract an entry x from the queue:
y = new entry
for i = 0 to 9 do
y.r = (x.r * 10 + i) % N
y.sum = x.sum + i
y.prev = <position of x in the queue>
y.lastDigit = i
if y.r == 0 and y.sum == N
// you found your multiple: use the prev and lastDigit entries to rebuild it
if y.sum < N then
queue.add(y)
This is basically a BFS on the digits. Since the maximum sum you care about is small, this should be pretty efficient.
After thinking about it a bit, I think I have found the expected answer.
Think of it as a graph. For any number, you can make new number by multiplying that number by 10 and adding any of the digits 0-9. You will need to use BFS to reach the smallest number first.
For every node maintain sum and remainder. Using these values you can move to the adjacent nodes, also these values will help you avoid reaching useless states again and again. To print the number, you can use these values to trace your steps.
Complexity is O(n^2), in worst case table is completely filled. (See code)
Note : Code takes number of test cases first. Works under 0.3s for n<=1000.
[Edit] : Ac on spoj in 6.54s. Test files have 50 numbers.
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define F first
#define S second
#define N 1100
#define mp make_pair
queue<pair<int, int> >Q;
short sumTrace[N][N], mulTrace[N][N];
void print(int sum, int mul) {
if (sumTrace[sum][mul] == 42)return;
print(sum-sumTrace[sum][mul], mulTrace[sum][mul]);
printf("%d",sumTrace[sum][mul]);
}
void solve(int n) {
Q.push(mp(0,0));
sumTrace[0][0]=42; // any number greater than 9
while (1) {
int sum = Q.front().F;
int mul = Q.front().S;
if (sum == n && mul == 0) break;
Q.pop();
for (int i=0; i<10; i++) {
int nsum = sum+i;
if (nsum > n)break;
int nmul = (mul*10+i)%n;
if (sumTrace[nsum][nmul] == -1) {
Q.push(mp(nsum, nmul));
sumTrace[nsum][nmul] = i;
mulTrace[nsum][nmul] = mul;
}
}
}
print(n,0);
while(!Q.empty())Q.pop();
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
memset(sumTrace, -1, sizeof sumTrace);
solve(n);
printf("\n");
}
return 0;
}