26 April 2021

I have never had a computer science class. I'd say I'm behind those people who graduated in the field for 48 months. I had to spend some time trying to understand what a CS student's bookshelf is like.

Although it's said that nothing is given so freely as advice, with a wish that what I listed up here is useful not only for myself but also for people, here I'm writing this article that is meant to provide a comprehensive map.

I'd stick to OPEN DATA STRUCTURES and PROJECT EULER mentioned at the bottom of this page, and use the rest of them as supplementary resources.

P.S. 25 November 2021

All is said and done, just take the FREE LECTURES OF PROFESSOR ROBERT SEDGEWICK on Coursera.

Useful materials

🎞️🎞️🎞️ Youtube playlist containing all videos listed in this page.

Computer architecture

🎞️ MIT, 9.2.3 The von Neumann Model
CPUs have the dedicated ADDRESS BUS in addition to the data bus.

🎞️ Inside the CPU - Computerphile
Address bus (2)

🎞️ Introduction to Von Neuman Architecture (Fetch-Decode-Execute) Cycle
Instructions LDD, ADD, STO, and data 27, 35 are stored in memory.
Addressing is the only way to tell the difference between them.
It's quite less than Javascripts' ===, the type considering equality.

🎞️ Tom Scott, The Fetch-Execute Cycle: What's Your Computer Actually Doing?
There's JUMP instruction, which will be described for the genesis of the subroutine later.

🎞️ The Calculator Wars: A video history of Japan's electronic industry (Part 3)
The bit part of the 64bit and 32bit CPU describes the addressible memory breadth. What is called usize/uintptr type, unsigned integer, 64bit length in the case of a x86_64 CPU.
Intel 4004 a 4bit processor. The capacity of an address will be mentioned in Open Data Structures as the word length.

🎞️ そろばんで3度目の日本一 西宮市の中3女子
The arithmetics with a set of circuits in CPU must be the same mechanism to a series of skills that the hands perform on a bit-wise abacus in fundamentals.

🎞️ Pointers and dynamic memory - stack vs heap
There are regions called STACK FRAMES for each function call.

🎞️ freeCodeCamp.org, Pointers in C / C++ [Full Course]
Jumping is enabled by means of the technique called function pointers, which allows us to use LOOP for example.
You might prefer to watch CS50 written below first.

🎞️ Wheeler Jump - Computerphile
Stories behind the subroutines

Software development

🎞️ CS50 2020 - Lecture 4 - Memory
Confirm the garbage values in memory and the undefined behaviour in C.

🎞️ CS50 2020 - Lecture 3 - Algorithms
Finding and comparison

🎞️ CS50 2020 - Lecture 5 - Data Structures
The physical restriction on the consective allocation extension, for the area is possibly already claimed by the other.

🎞️ Junmin Lee, Golang Tutorial 3 - Golang pointers explained, once and for all
Memory and the pointer in summary

Data structures and algorithms

🎞️ Fyi, MIT, Instruction-level Parallelism

Fyi, ARM architecture - conditional execution - Wikipedia


🎞️ freeCodeCamp, Data Structures Easy to Advanced Course - Full Tutorial from a Google Engineer
Comprehensive step by step tutorial about data structures. This allowed me to be familiar with their names and ready to read books about them.

🎞️ Spanning Tree, What is Binary Heap
There is sort of confusion in nomenclature, and watching these videos by Brian from CS50 at that time helped me to understand the 8h data structure tutorial.

🎞️ Spanning Tree, What Are Bloom Filters?

🎞️ Spanning Tree, How Dijkstra's Algorithm Works

🎞️ Spanning Tree, How Do You Calculate a Minimum Spanning Tree?

🎞️ Junmin Lee, Graph data structure and graph representation (Part 1 of 2)
It was helpful for me to watch this video at that point so as not to sink in the confusion.

🎞️ Junmin Lee, Data Structures and Algorithms in Go - Heaps


📖 Open Data Structures
It took me a while to know there was this book.

📖 Introduction to Algorithms, 3rd Edition (The MIT Press)
I couldn't find this book in my shallow previous research. I append this book here on 13 June 2021.

📖 Princeton University, Algorithms (4th Edition)
It seems to me that you wouldn't want this book if you already have Introduction to Algorithms, 3rd Edition. P.S. there's a complete online course.

📖 Algorithms in a Nutshell: A Practical Guide 2nd Edition
I flipped through all the pages. I'd stick to Open Data Structures.
It seems to me that you wouldn't want this book if you already have Introduction to Algorithms, 3rd Edition.

Additionally, it was comprehensive too. But I'd better stick to Open Data Structures.


📖 WILLEY, Data Structures and Algorithms in Java, 6th Edition
In fact I read only 4 out of 15 chapters. But it was nice to know about the generics dynamic dispatch and the parameters in Java are passed by value, such as badReset(Counter c) {c = new Counter();} //reassign local name c to a new Counter.

📖 SAMS, Data Structures and Algorithms in Java 2nd Edition
I haven't read it and probably it's not required if you have Open Data Structures.

Mathematics

🎞️🎞️🎞️ Youtube playlist

🖊️ Project Euler
I solved 33 questions so far and it helped me to remember mathematics and to know algorithms.

📖 The Concise Oxford Dictionary of Mathematics

📖 Mathematics Dictionary (5th ed) James & James

📖 Schaum's Outline of Mathematical Handbook of Formulas and Tables, Fifth Edition

📖 Collins Dictionary of Mathematics, by E. J. Borowski and J.M. Borwein

Compiler design

I haven't read them but it seems there are some chapters for data structures.

📖 Advanced Compiler Design and Implementation

📖 Compilers: Principles, Techniques, and Tools 2nd Edition

Further reading...

📖 Algorithms and Data Structures, Niklaus Wirth

📖 Algorithms in C, Robert Sedgewick

📖 A Simple Introduction to Graph Theory, Brian Heinold

📖 Introduction to Graph Theory (5th Edition) Robin J. Wilson

📖 アルゴリズム辞典 1994 (世田谷区図書館所蔵)

📖 C言語による最新アルゴリズム事典 (ソフトウェアテクノロジー) 奥村 晴彦

📖 最短経路の本 (世田谷区図書館所蔵)

📖 Cracking the Coding Interview: 189 Programming Questions and Solutions 6th Edition

📖 Brilliant.org Community Wiki

Dangling pointers and the alignment of composite data

Network interface controller, subnets and gateways

P.S. 7 December 2022 📖 [試して理解]Linuxのしくみ

PS

Data structures and algorithms might be easier than the non-pedagogical programming in a sense for its internal perfection and predictability.

I mean, I can imagine you are using Postman to check against a service that was provided by some organisation so that you can confirm the functionalities are implemented as described in their documents after experiencing irregular behaviours; you are collating the version of a Kubernetes' application in debugging for a runtime error that couldn't be detected with mock tests; or you are in a tunnel to find out idioms unheard of to write a passable Gradle script or an industrial level quality test code with the most up-to-date Mockito library with an extension that is also unheard of.

A warning says I must not click the back button in the browser. A question form doesn't have the option to choose for my answer. This kind of problem occurs regardless of using a computer or a sheet of paper.

As for me, having been stuck in quotidian affairs, I'm poor in certain things to be certified, which is not what I'm proud of. It definitely happens that you are busy with the handling of Authorization metadata of gRPC but have no chance to implement a MySQL of your own.

Problem 1 "Multiples of 3 or 5"

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

問 1 「3と5の倍数」

10未満の自然数のうち, 3 もしくは 5 の倍数になっているものは 3, 5, 6, 9 の4つがあり, これらの合計は 23 になる.

同じようにして, 1000 未満の 3 か 5 の倍数になっている数字の合計を求めよ.

struct ArithmeticProgression {
    first: i32,
    last: i32,
    diff: i32,
}

impl ArithmeticProgression {
    fn arithmetic_series(&self) -> i32 {
        assert!(self.diff != 0);
        assert!(
            (self.first > self.last) == (0 > self.diff),
            "The relationship between the first element and the last element \
            with the negativity of the common difference is incoherent."
        );
        let terms = (self.last - self.first) / self.diff + 1;
        assert!(
            self.first + self.diff * (terms - 1) == self.last,
            "The length between the first element, \
            the common difference and the last element is incoherent."
        );
        (self.first + self.last) * terms / 2
    }
}

fn main() {
    let a = ArithmeticProgression {
        first: 0,
        last: 999,
        diff: 3,
    }
    .arithmetic_series();
    let b = ArithmeticProgression {
        first: 0,
        last: 995,
        diff: 5,
    }
    .arithmetic_series();
    let ab = ArithmeticProgression {
        first: 0,
        last: 999 - 999 % 15,
        diff: 15,
    }
    .arithmetic_series();
    println!("{}", a + b - ab);
    assert_eq!(a + b - ab, 233168);

    assert_eq!(
        ArithmeticProgression {
            first: 2,
            last: 14,
            diff: 3
        }
        .arithmetic_series(),
        2 + 5 + 8 + 11 + 14
    );
    assert_eq!(
        ArithmeticProgression {
            first: 3,
            last: 12,
            diff: 3
        }
        .arithmetic_series(),
        3 + 6 + 9 + 12
    );
    assert_eq!(
        ArithmeticProgression {
            first: 1,
            last: 10,
            diff: 1
        }
        .arithmetic_series(),
        (1 + 10) * (10 / 2)
    );
    assert_eq!(
        ArithmeticProgression {
            first: -10,
            last: 10,
            diff: 1
        }
        .arithmetic_series(),
        0
    );
    assert_eq!(
        ArithmeticProgression {
            first: -4,
            last: 2,
            diff: 1
        }
        .arithmetic_series(),
        -4 - 3
    );
    assert_eq!(
        ArithmeticProgression {
            first: 5,
            last: -1,
            diff: -2
        }
        .arithmetic_series(),
        5 + 3 + 1 - 1
    );
    assert_eq!(
        ArithmeticProgression {
            first: 6,
            last: 0,
            diff: -2
        }
        .arithmetic_series(),
        6 + 4 + 2
    );
    assert_eq!(
        ArithmeticProgression {
            first: 6,
            last: 2,
            diff: -2
        }
        .arithmetic_series(),
        6 + 4 + 2
    );
    assert_eq!(
        ArithmeticProgression {
            first: -6,
            last: 0,
            diff: 2
        }
        .arithmetic_series(),
        -6 + -4 + -2
    );
    assert_eq!(
        ArithmeticProgression {
            first: -6,
            last: -2,
            diff: 2
        }
        .arithmetic_series(),
        -6 + -4 + -2
    );
}
package main

import (
	"fmt"
)

func arithmeticSeries(n uint32) uint32 {
	d := 999 / n
	return n * d * (d + 1) / 2
}

func Example() {
	ans := arithmeticSeries(3) + arithmeticSeries(5) - arithmeticSeries(15)
	fmt.Println(ans)
	// Output: 233168
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg)
  }
}

function arithmeticSeries(n: number): number {
  assert(Number.isInteger(n));
  assert(Math.sign(n) === 1, "Tried a negative n or division by zero.");
  const d = 999 / n | 0;
  return n * d * (d + 1) / 2 | 0;
}

const ans = arithmeticSeries(3) + arithmeticSeries(5) - arithmeticSeries(15);
console.log(ans);
assert(ans === 233168);
→ TypeScript playground
Problem 2 "Even Fibonacci numbers"

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

問 2 「偶数のフィボナッチ数」

フィボナッチ数列の項は前の2つの項の和である. 最初の2項を 1, 2 とすれば, 最初の10項は以下の通りである.

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

数列の項の値が400万以下のとき, 値が偶数の項の総和を求めよ.

struct TripleBox {
    i: u64,
    j: u64,
    k: u64,
}

impl TripleBox {
    fn shift(&mut self) {
        self.i = self.j + self.k;
        self.j = self.k + self.i;
        self.k = self.i + self.j;
    }
}

fn main() {
    let mut sum = 0;
    let mut tb = TripleBox { i: 0, j: 1, k: 1 };
    while tb.i <= 4_000_000 {
        sum += tb.i;
        tb.shift()
    }
    println!("{}", sum);
    assert_eq!(sum, 4613732)
}

struct LuckyClover {
    a: u64,
    b: u64,
    c: u64,
    d: u64,
}

impl LuckyClover {
    fn multiply(&mut self, other: &LuckyClover) {
        let a = self.a * other.a + self.b * other.c;
        let b = self.a * other.b + self.b * other.d;
        let c = self.c * other.a + self.d * other.c;
        let d = self.c * other.b + self.d * other.d;
        self.a = a;
        self.b = b;
        self.c = c;
        self.d = d;
    }
    fn identity_matrix() -> LuckyClover {
        LuckyClover {
            a: 1,
            b: 0,
            c: 0,
            d: 1,
        }
    }
}

fn main() {
    let multiplier = LuckyClover {
        a: 1,
        b: 1,
        c: 1,
        d: 0,
    };
    let cubed = {
        let mut i = LuckyClover::identity_matrix();
        i.multiply(&multiplier);
        i.multiply(&multiplier);
        i.multiply(&multiplier);
        std::mem::drop(multiplier);
        i
    };
    let mut sum = 0;
    let mut fibmatrix = LuckyClover::identity_matrix();
    while fibmatrix.b <= 4_000_000 {
        sum += fibmatrix.b;
        fibmatrix.multiply(&cubed);
    }
    println!("{}", sum);
    assert_eq!(sum, 4613732)
}
package main

import "fmt"

type Matrix struct {
	a, b, c, d uint64
}

func (m *Matrix) multiply(o Matrix) {
	m.a, m.b, m.c, m.d =
		m.a*o.a+m.b*o.c,
		m.a*o.b+m.b*o.d,
		m.c*o.a+m.d*o.c,
		m.c*o.b+m.d*o.d
}

func identityMatrix() Matrix {
	return Matrix{a: 1, b: 0, c: 0, d: 1}
}

func cube() Matrix {
	i := identityMatrix()
	fib := Matrix{a: 1, b: 1, c: 1, d: 0}
	i.multiply(fib)
	i.multiply(fib)
	i.multiply(fib)
	return i
}

func Example() {
	i := identityMatrix()
	c := cube()
	sum := uint64(0)
	for i.b <= 4_000_000 {
		sum += i.b
		i.multiply(c)
	}
	fmt.Println(sum)
	// Output: 4613732
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg)
  }
}

class Matrix {
  a: number;
  b: number;
  c: number;
  d: number;
  constructor() {
    this.a = 1;
    this.b = 0;
    this.c = 0;
    this.d = 1;
  }
  multiplyLiteral(o: { a: number; b: number; c: number; d: number }) {
    const a = this.a * o.a + this.b * o.c;
    const b = this.a * o.b + this.b * o.d;
    const c = this.c * o.a + this.d * o.c;
    const d = this.c * o.b + this.d * o.d;
    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;
  }
  multiplyMatrix(o: Matrix) {
    this.multiplyLiteral(o);
  }
}

function cube(): Matrix {
  let i = new Matrix();
  const fib = { a: 1, b: 1, c: 1, d: 0 };
  i.multiplyLiteral(fib);
  i.multiplyLiteral(fib);
  i.multiplyLiteral(fib);
  return i;
}

let i = new Matrix();
const c = cube();
let sum = 0;
while (i.b <= 4_000_000) {
  sum += i.b;
  i.multiplyMatrix(c);
} 
console.log(sum);
assert(sum === 4613732);
→ TypeScript playground

Problem 3 "Largest prime factor"

The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143 ?

問 3 「最大の素因数」

13195 の素因数は 5, 7, 13, 29 である.

600851475143 の素因数のうち最大のものを求めよ.

fn divide_fully(n: &mut u64, d: u64, side: &mut u64) {
    if *n % d != 0 {
        return;
    }
    while {
        *n /= d;
        *n % d == 0
    } {}
    *side = (*n as f64).sqrt() as u64;
}

fn largest_prime_factor(mut n: u64) -> u64 {
    assert!(n > 1);
    let mut side = (n as f64).sqrt() as u64;
    let basic_primes = [2u64, 3, 5];
    for &d in &basic_primes {
        divide_fully(&mut n, d, &mut side);
        if n == 1 {
            return d;
        }
    }
    let mut divisor = 5u64;
    for i in [2u64, 4].iter().cycle() {
        divisor += *i;
        if divisor > side {
            break;
        }
        divide_fully(&mut n, divisor, &mut side);
        if n == 1 {
            return divisor;
        }
    }
    n
}

fn main() {
    let ans = largest_prime_factor(600851475143u64);
    assert_eq!(ans, 6857);
    println!("{}", ans);
    assert_eq!(largest_prime_factor(60), 5);
    assert_eq!(largest_prime_factor(5), 5);
    assert_eq!(largest_prime_factor(17), 17);
    assert_eq!(largest_prime_factor(6), 3);
    assert_eq!(largest_prime_factor(15), 5);
    assert_eq!(largest_prime_factor(25698751364526), 328513);
    assert_eq!(largest_prime_factor(13195), 29);
}

fn largest_prime_factor(mut n: u64) -> u64 {
    assert!(n > 1);
    let mut divisor = 2u64;
    while n != 1 {
        if n % divisor == 0 {
            n /= divisor;
        } else {
            divisor += 1;
        }
    }
    divisor
}

fn main() {
    let ans = largest_prime_factor(600851475143u64);
    assert_eq!(ans, 6857);
    println!("{}", ans);
    assert_eq!(largest_prime_factor(60), 5);
    assert_eq!(largest_prime_factor(5), 5);
    assert_eq!(largest_prime_factor(17), 17);
    assert_eq!(largest_prime_factor(6), 3);
    assert_eq!(largest_prime_factor(15), 5);
    assert_eq!(largest_prime_factor(25698751364526), 328513);
    assert_eq!(largest_prime_factor(13195), 29);
}
package main

import (
	"fmt"
	"log"
	"math"
)

func divideFully(n *uint64, d uint64, side *uint64) {
	if *n%d != 0 {
		return
	}
	for ok := true; ok; ok = *n%d == 0 {
		*n /= d
	}
	*side = uint64(math.Sqrt(float64(*n)))
}

type Divisor struct {
	d uint64
	f uint8
}

func (d *Divisor) increment() {
	d.d += uint64(2) << d.f
	d.f ^= 1
}

func largestPrimeFactor(n uint64) uint64 {
	if n < 2 {
		log.Fatal("n must be > 1.")
	}
	side := uint64(math.Sqrt(float64(n)))
	for _, d := range []uint64{2, 3, 5} {
		divideFully(&n, d, &side)
		if n == 1 {
			return d
		}
	}
	d := Divisor{d: 5}
	for {
		d.increment()
		if d.d > side {
			break
		}
		divideFully(&n, d.d, &side)
		if n == 1 {
			return d.d
		}
	}
	return n
}

func Example() {
	ans := largestPrimeFactor(600851475143)
	fmt.Println(ans)
	// Output: 6857
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

class Divisor {
  d: number;
  #f: number;
  constructor() {
    this.d = 5;
    this.#f = 0;
  }
  increment() {
    this.d += 2 << this.#f;
    this.#f ^= 1;
  }
}

function divideFully(n: number, d: number, side: number): [number, number] {
  if (n % d != 0) {
    return [n, side];
  }
  do {
    n /= d | 0;
  } while (n % d === 0);
  return [n, Math.sqrt(n) | 0];
}

function largestPrimeFactor(n: number): number {
  assert(Number.isInteger(n));
  assert(n > 1);
  let side = Math.sqrt(n) | 0;
  for (const d of [2, 3, 5]) {
    [n, side] = divideFully(n, d, side);
    if (n === 1) {
      return d;
    }
  }
  const d = new Divisor();
  while (true) {
    d.increment();
    if (d.d > side) {
      break;
    }
    [n, side] = divideFully(n, d.d, side);
    if (n === 1) {
      return d.d;
    }
  }
  return n;
}

let ans = largestPrimeFactor(600851475143);
console.log(ans);
assert(ans === 6857);
→ TypeScript playground
Problem 4 "Largest palindrome product"

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.

Find the largest palindrome made from the product of two 3-digit numbers.

問 4 「最大の回文積」

左右どちらから読んでも同じ値になる数を回文数という. 2桁の数の積で表される回文数のうち, 最大のものは 9009 = 91 × 99 である.

では, 3桁の数の積で表される回文数の最大値を求めよ.

fn is_palindrome(a: u32) -> bool {
    let mut t = a;
    let mut b = 0u32;
    while t > 0 {
        b *= 10;
        b += t % 10;
        t /= 10;
    }
    a == b
}

fn update_largest_palindrome_product(lpp: &mut Option<u32>, with: u32) {
    match lpp.as_mut() {
        Some(v) => *v = with,
        None => *lpp = Some(with),
    }
}

fn scan_b(a: u32, largest_pp: &mut Option<u32>) {
    for b in (a..=999).rev() {
        let p = a * b;
        if p <= largest_pp.unwrap_or_default() {
            return;
        }
        if is_palindrome(p) {
            update_largest_palindrome_product(largest_pp, p);
        }
    }
}

fn main() {
    let mut largest_pal_pro: Option<u32> = None;
    for a in (110..=990).rev().step_by(11) {
        scan_b(a, &mut largest_pal_pro);
    }
    let ans = largest_pal_pro.unwrap();

    println!("{}", ans);
    assert_eq!(ans, 906609);
}
package main

import "fmt"

func isPalindrome(p int) bool {
	t := int(p)
	q := 0
	for t > 0 {
		q = q*10 + t%10
		t /= 10
	}
	return p == q
}

func scanB(a, lpp int) int {
	for b := 999; b >= a; b-- {
		p := a * b
		if p <= lpp {
			return lpp
		}
		if !isPalindrome(p) {
			continue
		}
		if p > lpp {
			lpp = p
		}
	}
	return lpp
}

func Example() {
	lpp := 0
	for a := 990; a >= 110; a -= 11 {
		lpp = scanB(a, lpp)
	}
	fmt.Println(lpp)
	// Output: 906609
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

function isPalindrome(p: number): boolean {
  let t = Number(p);
  let q = 0;
  while (t > 0) {
    q = q * 10 + t % 10;
    t = t / 10 | 0;
  }
  return p === q;
}

function scanB(a: number, lpp: number): number {
  for (let b = 999; b >= a; b--) {
    const p = a * b;
    if (p <= lpp) {
      return lpp;
    }
    if (isPalindrome(p)) {
      lpp = Math.max(lpp, p);
    }
  }
  return lpp;
}

let lpp = 0;
for (let a = 990; a >= 110; a -= 11) {
  lpp = scanB(a, lpp);
}
console.log(lpp);
assert(lpp === 906609);
→ TypeScript playground
Problem 5 "Smallest multiple"

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

問 5 「最小の倍数」

2520 は 1 から 10 の数字の全ての整数で割り切れる数字であり, そのような数字の中では最小の値である.

では, 1 から 20 までの整数全てで割り切れる数字の中で最小の正の数はいくらになるか.


fn gcd(mut a: u64, mut b: u64) -> u64 {
    assert!(a != 0 && b != 0);
    while b != 0 {
        let r = a % b;
        a = b;
        b = r;
    }
    a
}

fn lcm(a: u64, b: u64) -> u64 {
    a * b / gcd(a, b)
}

fn main() {
    let mut acc = 2u64;
    for n in 3..=20u64 {
        acc = lcm(acc, n);
    }

    println!("{}", acc);
    assert_eq!(acc, 232792560);
}

#[derive(Clone)]
struct Factor {
    prime: u32,
    occurrence: u32,
}

fn increment_occurrence(factors: &mut [Option<Factor>; 20], p: u32) {
    if let Some(f) = factors[p as usize].as_mut() {
        f.occurrence += 1;
        return;
    }
    factors[p as usize] = Some(Factor {
        prime: p,
        occurrence: 1,
    });
}

fn list_factors(mut n: u32) -> [Option<Factor>; 20] {
    assert!(n <= 20);
    let mut factors: [Option<Factor>; 20] = Default::default();
    let mut d = 2u32;
    while n > 1 {
        while n % d == 0 {
            increment_occurrence(&mut factors, d);
            n /= d;
        }
        d += 1;
    }
    factors
}

fn merge(factors: &mut [Option<Factor>; 20], b: &[Option<Factor>; 20]) {
    for it in b.iter().zip(factors.iter_mut()) {
        match it {
            (Some(bf), None) => *it.1 = Some(bf.clone()),
            (Some(bf), Some(f)) if bf.occurrence > f.occurrence => {
                f.occurrence = bf.occurrence
            },
            _ => continue,
        }
    }
}

fn main() {
    let mut factors: [Option<Factor>; 20] = Default::default();
    for n in 2..=20u32 {
        let local_factors = list_factors(n);
        merge(&mut factors, &local_factors);
    }
    let mut acc = 1u32;
    for o in &factors {
        if let Some(f) = o {
            acc *= f.prime.pow(f.occurrence);
        }
    }

    println!("{}", acc);
    assert_eq!(acc, 232792560);
}
package main

import (
	"fmt"
	"log"
)

func gcd(a, b uint64) uint64 {
	if a == 0 || b == 0 {
		log.Fatal("gcd(0) is undefined.")
	}
	for b != 0 {
		a, b = b, a%b
	}
	return a
}

func lcm(a, b uint64) uint64 {
	return a * b / gcd(a, b)
}

func Example() {
	acc := uint64(2)
	for n := uint64(3); n <= 20; n++ {
		acc = lcm(acc, n)
	}
	fmt.Println(acc)
	// Output: 232792560
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

function gcd(a: number, b: number): number {
  assert(Number.isInteger(a) && Number.isInteger(b));
  assert(Math.sign(a) === 1 && Math.sign(b) === 1);
  let t: number;
  while (b != 0) {
    t = Number(a);
    a = b;
    b = t % b;
  }
  return a;
}

function lcm(a: number, b: number): number {
  return a * b / gcd(a, b);
}

let acc = 2;
for (let n = 3; n <= 20; n++) {
  acc = lcm(acc, n);
}
console.log(acc);
assert(acc === 232792560);
→ TypeScript playground
Problem 6 "Sum square difference"

The sum of the squares of the first ten natural numbers is,

$$1^2 + 2^2 + ... + 10^2 = 385$$

The square of the sum of the first ten natural numbers is,

$$(1 + 2 + ... + 10)^2 = 55^2 = 3025$$

Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 - 385 = 2640.

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

問 6 「二乗和の差」

最初の10個の自然数について, その二乗の和は,

$$1^2 + 2^2 + ... + 10^2 = 385$$

最初の10個の自然数について, その和の二乗は,

$$(1 + 2 + ... + 10)^2 = 55^2 = 3025$$

これらの数の差は 3025 - 385 = 2640 となる.

同様にして, 最初の100個の自然数について二乗の和と和の二乗の差を求めよ.

struct Sequence {
    n: u64,
}

impl Sequence {
    fn sum_of_squares(&self) -> u64 {
        self.n * (self.n + 1) * (2 * self.n + 1) / 6
    }
    fn sum(&self) -> u64 {
        (1 + self.n) * self.n / 2
    }
}

fn main() {
    let s = Sequence{n: 100};
    let sum = s.sum();
    let diff = sum * sum - s.sum_of_squares();

    println!("{}", diff);
    assert_eq!(diff, 25164150);
}
package main

import "fmt"

type Sequence struct {
	n uint64
}

func (s *Sequence) sumOfSquares() uint64 {
	return s.n * (s.n + 1) * (2*s.n + 1) / 6
}

func (s *Sequence) sum() uint64 {
	return (1 + s.n) * s.n / 2
}

func Example() {
	s := Sequence{n: 100}
	sum := s.sum()
	diff := sum*sum - s.sumOfSquares()
	fmt.Println(diff)
	// Output: 25164150
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

interface Sequence {
  n: number;
}

function sumOfSquares(s: Sequence): number {
  return s.n * (s.n + 1) * (2 * s.n + 1) / 6;
}

function sum(s: Sequence): number {
  return (1 + s.n) * s.n / 2;
}

const s: Sequence = { n: 100 };
const su = sum(s);
const diff = su * su - sumOfSquares(s);
console.log(diff);
assert(diff === 25164150);
→ TypeScript playground
Problem 7 "10001st prime"

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.

What is the 10 001st prime number?

問 7 「10001番目の素数」

素数を小さい方から6つ並べると 2, 3, 5, 7, 11, 13 であり, 6番目の素数は 13 である.

10 001 番目の素数を求めよ.

fn rule_out(sieve: &mut Vec<bool>, prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn rule_out_from_previous_position(sieve: &mut Vec<bool>, prime: usize, pp: usize) {
    use std::cmp::max;
    let begin = max((((pp - 1) / prime) + 1) * prime, prime * prime);
    for i in (begin..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn extend(sieve: &mut Vec<bool>, primes: &Vec<usize>) {
    let previous_len = sieve.len();
    sieve.extend(vec![true; previous_len]);
    for &p in primes {
        rule_out_from_previous_position(sieve, p, previous_len);
    }
}

fn main() {
    let mut counter = 2u32;
    let mut sieve = vec![true; 10000];
    let mut primes: Vec<usize> = vec![];
    let mut cursor = 5usize;
    let mut ite = [2usize, 4].iter().cycle();
    let n = 'exploration: loop {
        while cursor < sieve.len() {
            if !sieve[cursor] {
                cursor += ite.next().unwrap();
                continue;
            }
            counter += 1;
            if counter == 10001 {
                break 'exploration cursor as u64;
            }
            &primes.push(cursor);
            rule_out(&mut sieve, cursor);
            cursor += ite.next().unwrap();
        }
        extend(&mut sieve, &primes);
    };

    println!("{}", n);
    assert_eq!(n, 104743);
}

fn is_prime(n: u64) -> bool {
    if n < 2 {
        return false;
    }
    if n == 2 || n == 3 || n == 5 {
        return true;
    }
    for d in &[2u64, 3, 5] {
        if n % *d == 0 {
            return false;
        }
    }
    let side = (n as f64).sqrt() as u64;
    let mut d = 5u64;
    for i in [2u64, 4].iter().cycle() {
        d += *i;
        if d > side {
            break;
        }
        if n % d == 0 {
            return false;
        }
    }
    true
}

fn main() {
    let mut n = 0u64;
    let mut counter = 0u32;
    while counter < 10001 {
        n += 1;
        if is_prime(n) {
            counter += 1;
        }
    }
    
    println!("{}", n);
    assert_eq!(n, 104743);
}
package main

import "fmt"

type Index struct {
	i int
	f uint8
}

func (i *Index) increment() {
	i.i += 2 << i.f
	i.f ^= 1
}

func ruleout(sieve []bool, p int) {
	for i := p * p; i < len(sieve); i += p {
		sieve[i] = true
	}
}

func ruleoutFromPosition(sieve []bool, prime, position int) {
	pos := (((position - 1) / prime) + 1) * prime
	sq := prime * prime
	if pos < sq {
		pos = sq
	}
	for i := pos; i < len(sieve); i += prime {
		sieve[i] = true
	}
}

func extend(sieve *[]bool, primes []int) {
	previousLen := len(*sieve)
	*sieve = append(*sieve, make([]bool, previousLen)...)
	for _, p := range primes {
		ruleoutFromPosition(*sieve, p, previousLen)
	}
}

func Example() {
	counter := 2
	sieve := make([]bool, 10000)
	primes := []int{}
	i := Index{i: 5}
Exploration:
	for {
		for i.i < len(sieve) {
			if sieve[i.i] {
				i.increment()
				continue
			}
			counter++
			if counter == 10001 {
				break Exploration
			}
			primes = append(primes, i.i)
			ruleout(sieve, i.i)
			i.increment()
		}
		extend(&sieve, primes)
	}
	fmt.Println(i.i)
	// Output: 104743
}

https://stackoverflow.com/questions/23304854/how-do-you-determine-if-a-variable-is-a-slice-or-array

→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

class Index {
  i: number;
  #f: number;
  constructor() {
    this.i = 5;
    this.#f = 0;
  }
  increment() {
    this.i += 2 << this.#f;
    this.#f ^= 1;
  }
}

function ruleoutFromPosition(
  sieve: boolean[],
  prime: number,
  position: number,
) {
  const sq = prime * prime;
  const head = (((position - 1) / prime | 0) + 1) * prime;
  for (let i = Math.max(sq, head); i < sieve.length; i += prime) {
    sieve[i] = false;
  }
}

function ruleout(sieve: boolean[], p: number) {
  for (let i = p * p; i < sieve.length; i += p) {
    sieve[i] = false;
  }
}

function extend(sieve: boolean[], primes: number[]) {
  const previousLen = sieve.length;
  sieve.push(...Array(previousLen).fill(true));
  for (const p of primes) {
    ruleoutFromPosition(sieve, p, previousLen);
  }
}

let counter = 2;
let sieve = Array(10000).fill(true);
let primes = [];
const i = new Index();
exploration:
while (true) {
  while (i.i < sieve.length) {
    if (!sieve[i.i]) {
      i.increment();
      continue;
    }
    counter++;
    if (counter === 10001) {
      break exploration;
    }
    primes.push(i.i);
    ruleout(sieve, i.i);
    i.increment();
  }
  extend(sieve, primes);
}
console.log(i.i);
assert(i.i === 104743);
→ TypeScript playground
Problem 8 "Largest product in a series"

The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.

73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450

Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?

問 8 「数字列中の最大の積」

次の1000桁の数字のうち, 隣接する4つの数字の総乗の中で, 最大となる値は, 9 × 9 × 8 × 9 = 5832である.

この1000桁の数字から13個の連続する数字を取り出して, それらの総乗を計算する. では、それら総乗のうち、最大となる値はいくらか.

EX 6桁の数123789から5個の連続する数字を取り出す場合, 12378と23789の二通りとなり, 後者の23789=3024が最大の総乗となる.

fn main() {
    let thousand_digits = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
    let zero = '0' as u8;
    let digits = thousand_digits
        .chars()
        .map(|c| c as u8 - zero)
        .collect::<Vec<u8>>();
    let mut max = 0u64;
    for i in 0..digits.len() - 13 {
        let tmp = digits[i..i + 13].iter().map(|&d| d as u64).product();
        max = std::cmp::max(max, tmp);
    }

    println!("{}", max);
    assert_eq!(max, 23514624000);
}
fn main() {
    let thousand_digits = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
    let zero = '0' as u8;
    let digits = thousand_digits
        .chars()
        .map(|c| c as u8 - zero)
        .collect::<Vec<u8>>();
    let mut product = digits[0..=12].iter().map(|&d| d as u64).product::<u64>();
    let mut max = product.clone();
    for i in 13..digits.len() {
        let outgoing = digits[i - 13];
        if outgoing == 0 {
            product = digits[i - 12..=i].iter().map(|&d| d as u64).product();
        } else {
            product /= outgoing as u64;
            product *= digits[i] as u64;
        }
        max = std::cmp::max(max, product);
    }

    println!("{}", max);
    assert_eq!(max, 23514624000);
}

With go and javascript, the memorization made it faster.

package main

import "fmt"

// 22810 ns/op
func ExampleA() {
	thousandDigits := "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450"
	zero := int('0')
	runes := []rune(thousandDigits)
	digits := make([]int, len(runes))
	for i, r := range runes {
		digits[i] = int(r) - zero
	}
	max := 0
	for i := 0; i < len(digits)-13; i++ {
		product := digits[i]
		for _, v := range digits[i+1 : i+13] {
			product *= v
		}
		if max < product {
			max = product
		}
	}
	fmt.Println(max)
	// Output: 23514624000
}

// 10994 ns/op
func ExampleB() {
	thousandDigits := "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450"
	zero := int('0')
	runes := []rune(thousandDigits)
	digits := make([]int, len(runes))
	for i, r := range runes {
		digits[i] = int(r) - zero
	}
	product := 1
	for _, v := range digits[0:13] {
		product *= v
	}
	max := int(product)
	for i := 13; i < len(digits); i++ {
		outgoing := digits[i-13]
		if outgoing == 0 {
			product = digits[i]
			for _, v := range digits[i-12 : i] {
				product *= v
			}
		} else {
			product /= outgoing
			product *= digits[i]
		}
		if max < product {
			max = product
		}
	}
	fmt.Println(max)
	// Output: 23514624000
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

// 118 us
function a() {
  const thousandDigits =
    "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
  const zero = "0".charCodeAt(0);
  const chars = Array.from(thousandDigits);
  const digits = chars.map((c) => c.charCodeAt(0) - zero);
  let max = 0;
  for (let i = 0; i < digits.length - 13; i++) {
    const product = digits.slice(i, i + 13).reduce((acc, v) => acc * v);
    max = Math.max(max, product);
  }
  console.log(max);
  assert(max === 23514624000);
}

// 52 us
function b() {
  const thousandDigits =
    "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
  const zero = "0".charCodeAt(0);
  const chars = Array.from(thousandDigits);
  const digits = chars.map((c) => c.charCodeAt(0) - zero);
  let product = digits.slice(0, 13).reduce((acc, v) => acc * v);
  let max = Number(product);
  for (let i = 13; i < digits.length; i++) {
    const outgoing = digits[i - 13];
    if (outgoing == 0) {
      product = digits.slice(i - 12, i + 1).reduce((acc, v) => acc * v);
    } else {
      product /= outgoing;
      product *= digits[i];
    }
    max = Math.max(max, product);
  }
  console.log(max);
  assert(max === 23514624000);
}

a();
b();
→ TypeScript playground
Problem 9 "Special Pythagorean triplet"

A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,

a2 + b2 = c2

For example, 32 + 42 = 9 + 16 = 25 = 52.

There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc.

問 9 「特別なピタゴラス数」

ピタゴラス数(ピタゴラスの定理を満たす自然数)とは a < b < c で以下の式を満たす数の組である.

a2 + b2 = c2

例えば, 32 + 42 = 9 + 16 = 25 = 52 である.

a + b + c = 1000 となるピタゴラスの三つ組が一つだけ存在する.

これらの積 abc を計算しなさい.

fn main() {
    let mut ans = None;
    'exploration: for m in 2..=(499f32.sqrt() as u32) {
        for n in 1..m {
            let a = m * m - n * n;
            let b = 2 * m * n;
            let c = m * m + n * n;
            if a + b + c == 1000 {
                ans = Some(a * b * c);
                break 'exploration;
            }
        }
    }

    println!("{:?}", ans);
    assert_eq!(ans.unwrap(), 31875000);
}
package main

import (
	"fmt"
	"math"
	"testing"
)

func Example() {
	var ans uint32
Exploration:
	for m := uint32(2); m <= uint32(math.Sqrt(float64(499))); m++ {
		for n := uint32(1); n < m; n++ {
			a := m*m - n*n
			b := 2 * m * n
			c := m*m + n*n
			if a+b+c == 1000 {
				ans = a * b * c
				break Exploration
			}
		}
	}
	fmt.Println(ans)
	// Output: 31875000
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

let ans = 0;
exploration:
for (let m = 2; m <= (Math.sqrt(499) | 0); m++) {
  for (let n = 1; n < m; n++) {
    const a = m * m - n * n;
    const b = 2 * m * n;
    const c = m * m + n * n;
    if (a + b + c === 1000) {
      ans = a * b * c;
      break exploration;
    }
  }
}
console.log(ans);
assert(ans === 31875000);
→ TypeScript playground
Problem 10 "Summation of primes"

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.

問 10 「素数の和」

10以下の素数の和は 2 + 3 + 5 + 7 = 17 である.

200万以下の全ての素数の和を求めよ.

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

fn rule_out(sieve: &mut [bool; 2_000_001], prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn main() {
    let mut sieve = [true; 2_000_001];
    let sqrt = ((sieve.len() - 1) as f64).sqrt() as usize;
    let mut sum = 2u64 + 3;
    let mut index = Index::new();
    while index.i <= sqrt {
        if sieve[index.i] {
            sum += index.i as u64;
            rule_out(&mut sieve, index.i);
        }
        index.increment();
    }
    while index.i < sieve.len() {
        if sieve[index.i] {
            sum += index.i as u64;
        }
        index.increment();
    }

    println!("{}", sum);
    assert_eq!(sum, 142913828922);
}
mod index {
    pub struct Index {
        pub i: usize,
        ite: Box<dyn Iterator<Item = usize>>,
    }
    impl Index {
        pub fn increment(&mut self) {
            self.i += self.ite.next().unwrap();
        }
        pub fn new() -> Self {
            Self {
                i: 5,
                ite: Box::new(vec![2usize, 4].into_iter().cycle()),
            }
        }
    }
}

fn rule_out(sieve: &mut [bool; 2_000_001], prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn main() {
    let mut sieve = [true; 2_000_001];
    let sqrt = ((sieve.len() - 1) as f64).sqrt() as usize;
    let mut sum = 2u64 + 3;
    let mut index = index::Index::new();
    while index.i <= sqrt {
        if sieve[index.i] {
            sum += index.i as u64;
            rule_out(&mut sieve, index.i);
        }
        index.increment();
    }
    while index.i < sieve.len() {
        if sieve[index.i] {
            sum += index.i as u64;
        }
        index.increment();
    }

    println!("{}", sum);
    assert_eq!(sum, 142913828922);
}

package main

import (
	"fmt"
	"math"
	"testing"
)

type Index struct {
	i int
	f uint8
}

func (i *Index) increment() {
	i.i += 2 << i.f
	i.f ^= 1
}

func ruleout(sieve []bool, p int) {
	for i := p * p; i < len(sieve); i += p {
		sieve[i] = true
	}
}

func Example() {
	n := 2_000_000
	sieve := make([]bool, n+1)
	side := int(math.Sqrt(float64(n)))
	i := Index{i: 5}
	sum := 2 + 3
	for i.i <= side {
		if !sieve[i.i] {
			ruleout(sieve, i.i)
			sum += i.i
		}
		i.increment()
	}
	for i.i < len(sieve) {
		if !sieve[i.i] {
			sum += i.i
		}
		i.increment()
	}

	fmt.Println(sum)
	// Output: 142913828922
}
→ Go playground
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

class Index {
  i: number;
  #f: number;
  constructor() {
    this.i = 5;
    this.#f = 0;
  }
  increment() {
    this.i += 2 << this.#f;
    this.#f ^= 1;
  }
}

function ruleout(sieve: boolean[], p: number) {
  for (let i = p * p; i < sieve.length; i += p) {
    sieve[i] = false;
  }
}

const n = 2_000_000;
let sieve = Array(n + 1).fill(true);
const side = Math.sqrt(n) | 0;
let sum = 2 + 3;
const i = new Index();
while (i.i <= side) {
  if (sieve[i.i]) {
    sum += i.i;
    ruleout(sieve, i.i);
  }
  i.increment();
}
while (i.i < sieve.length) {
  if (sieve[i.i]) {
    sum += i.i;
  }
  i.increment();
}
console.log(sum);
assert(sum === 142913828922);
→ TypeScript playground
Problem 11 "Largest product in a grid"

In the 20×20 grid below, four numbers along a diagonal line have been marked in red.

08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48

The product of these numbers is 26 × 63 × 78 × 14 = 1788696.

What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in the 20×20 grid?

問 11 「格子内の最大の積」

上の 20×20 の格子のうち, 斜めに並んだ4つの数字が赤くマークされている.

それらの数字の積は 26 × 63 × 78 × 14 = 1788696 となる.

上の 20×20 の格子のうち, 上下左右斜めのいずれかの方向で連続する4つの数字の積のうち最大のものはいくつか?

fn main() {
    let matrix = MATRIX;
    let mut max = 0u32;

    // →
    for y in matrix {
        for x in 3..matrix.len() {
            if let (Some(a), Some(b), Some(c), Some(d)) =
                (y.get(x - 3), y.get(x - 2), y.get(x - 1), y.get(x))
            {
                max = std::cmp::max(max, a * b * c * d);
            }
        }
    }

    // ↓
    for x in 0..matrix.len() {
        for y in 3..matrix.len() {
            if let (Some(a), Some(b), Some(c), Some(d)) = (
                matrix.get(y - 3).and_then(|r| r.get(x)),
                matrix.get(y - 2).and_then(|r| r.get(x)),
                matrix.get(y - 1).and_then(|r| r.get(x)),
                matrix.get(y).and_then(|r| r.get(x)),
            ) {
                max = std::cmp::max(max, a * b * c * d);
            }
        }
    }

    // ↘
    for x in 3..matrix.len() {
        for y in 3..matrix.len() {
            if let (Some(a), Some(b), Some(c), Some(d)) = (
                matrix.get(y - 3).and_then(|r| r.get(x - 3)),
                matrix.get(y - 2).and_then(|r| r.get(x - 2)),
                matrix.get(y - 1).and_then(|r| r.get(x - 1)),
                matrix.get(y).and_then(|r| r.get(x)),
            ) {
                max = std::cmp::max(max, a * b * c * d);
            }
        }
    }

    // ↙
    for x in 3..matrix.len() {
        for y in 0..matrix.len() - 3 {
            if let (Some(a), Some(b), Some(c), Some(d)) = (
                matrix.get(y + 3).and_then(|r| r.get(x - 3)),
                matrix.get(y + 2).and_then(|r| r.get(x - 2)),
                matrix.get(y + 1).and_then(|r| r.get(x - 1)),
                matrix.get(y).and_then(|r| r.get(x)),
            ) {
                max = std::cmp::max(max, a * b * c * d);
            }
        }
    }

    println!("{}", max);
    assert_eq!(max, 70600674);
}

const MATRIX: [[u32; 20]; 20] = [
    [08, 02, 22, 97, 38, 15, 00, 40, 00, 75, 04, 05, 07, 78, 52, 12, 50, 77, 91, 08,],
    [49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 04, 56, 62, 00,],
    [81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 03, 49, 13, 36, 65,],
    [52, 70, 95, 23, 04, 60, 11, 42, 69, 24, 68, 56, 01, 32, 56, 71, 37, 02, 36, 91,],
    [22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80,],
    [24, 47, 32, 60, 99, 03, 45, 02, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50,],
    [32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70,],
    [67, 26, 20, 68, 02, 62, 12, 20, 95, 63, 94, 39, 63, 08, 40, 91, 66, 49, 94, 21,],
    [24, 55, 58, 05, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72,],
    [21, 36, 23, 09, 75, 00, 76, 44, 20, 45, 35, 14, 00, 61, 33, 97, 34, 31, 33, 95,],
    [78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 03, 80, 04, 62, 16, 14, 09, 53, 56, 92,],
    [16, 39, 05, 42, 96, 35, 31, 47, 55, 58, 88, 24, 00, 17, 54, 24, 36, 29, 85, 57,],
    [86, 56, 00, 48, 35, 71, 89, 07, 05, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58,],
    [19, 80, 81, 68, 05, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 04, 89, 55, 40,],
    [04, 52, 08, 83, 97, 35, 99, 16, 07, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66,],
    [88, 36, 68, 87, 57, 62, 20, 72, 03, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69,],
    [04, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 08, 46, 29, 32, 40, 62, 76, 36,],
    [20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 04, 36, 16,],
    [20, 73, 35, 29, 78, 31, 90, 01, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 05, 54,],
    [01, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 01, 89, 19, 67, 48,],
];

struct Square {
    _matrix: [[u32; 20]; 20],
    _x: usize,
    _y: usize,
    _width: usize,
}

impl Square {
    fn new(matrix: [[u32; 20]; 20]) -> Self {
        assert!(matrix.len() == 0 || matrix.len() == matrix[0].len());
        Self {
            _x: 0,
            _y: 0,
            _matrix: matrix,
            _width: matrix.len(),
        }
    }
    fn width(&self) -> usize {
        self._width
    }
    fn set_cursor(&mut self, x: usize, y: usize) {
        self._x = x;
        self._y = y;
    }
    fn east_product(&self, adj_len: usize) -> Result<u32, ()> {
        if self._x + adj_len > self._matrix.len() {
            return Err(());
        }
        let p = (0..adj_len)
            .map(|a| self._matrix[self._y][self._x + a])
            .product::<u32>();
        Ok(p)
    }
    fn south_product(&self, adj_len: usize) -> Result<u32, ()> {
        if self._y + adj_len > self._matrix.len() {
            return Err(());
        }
        let p = (0..adj_len)
            .map(|a| self._matrix[self._y + a][self._x])
            .product::<u32>();
        Ok(p)
    }
    fn south_east_product(&self, adj_len: usize) -> Result<u32, ()> {
        if self._y + adj_len > self._matrix.len() {
            return Err(());
        }
        if self._x + adj_len > self._matrix.len() {
            return Err(());
        }
        let p = (0..adj_len)
            .map(|a| self._matrix[self._y + a][self._x + a])
            .product::<u32>();
        Ok(p)
    }
    fn south_west_product(&self, adj_len: usize) -> Result<u32, ()> {
        if self._y + adj_len > self._matrix.len() {
            return Err(());
        }
        if self._x < adj_len - 1 {
            return Err(());
        }
        let p = (0..adj_len)
            .map(|a| self._matrix[self._y + a][self._x - a])
            .product::<u32>();
        Ok(p)
    }
}

fn main() {
    let mut square = Square::new(MATRIX);

    let mut max = 0u32;
    for i in 0..square.width() {
        for j in 0..square.width() {
            square.set_cursor(i, j);
            if let Ok(p) = square.east_product(4) {
                max = std::cmp::max(max, p);
            }
            if let Ok(p) = square.south_product(4) {
                max = std::cmp::max(max, p);
            }
            if let Ok(p) = square.south_east_product(4) {
                max = std::cmp::max(max, p);
            }
            if let Ok(p) = square.south_west_product(4) {
                max = std::cmp::max(max, p);
            }
        }
    }

    println!("{}", max);
    assert_eq!(max, 70600674);
}


const MATRIX: [[u32; 20]; 20] = [
    [08, 02, 22, 97, 38, 15, 00, 40, 00, 75, 04, 05, 07, 78, 52, 12, 50, 77, 91, 08,],
    [49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 04, 56, 62, 00,],
    [81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 03, 49, 13, 36, 65,],
    [52, 70, 95, 23, 04, 60, 11, 42, 69, 24, 68, 56, 01, 32, 56, 71, 37, 02, 36, 91,],
    [22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80,],
    [24, 47, 32, 60, 99, 03, 45, 02, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50,],
    [32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70,],
    [67, 26, 20, 68, 02, 62, 12, 20, 95, 63, 94, 39, 63, 08, 40, 91, 66, 49, 94, 21,],
    [24, 55, 58, 05, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72,],
    [21, 36, 23, 09, 75, 00, 76, 44, 20, 45, 35, 14, 00, 61, 33, 97, 34, 31, 33, 95,],
    [78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 03, 80, 04, 62, 16, 14, 09, 53, 56, 92,],
    [16, 39, 05, 42, 96, 35, 31, 47, 55, 58, 88, 24, 00, 17, 54, 24, 36, 29, 85, 57,],
    [86, 56, 00, 48, 35, 71, 89, 07, 05, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58,],
    [19, 80, 81, 68, 05, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 04, 89, 55, 40,],
    [04, 52, 08, 83, 97, 35, 99, 16, 07, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66,],
    [88, 36, 68, 87, 57, 62, 20, 72, 03, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69,],
    [04, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 08, 46, 29, 32, 40, 62, 76, 36,],
    [20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 04, 36, 16,],
    [20, 73, 35, 29, 78, 31, 90, 01, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 05, 54,],
    [01, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 01, 89, 19, 67, 48,],
];

They both store data in a linear contiguous array where accessing or iterating is both an O(1) operation so there's no difference in performance.

Performance of Rust vector (Vec<T>) versus array ([T; n]) [closed]

Problem 12 "Highly divisible triangular number"

The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

Let us list the factors of the first seven triangle numbers:

1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28

We can see that 28 is the first triangle number to have over five divisors.

What is the value of the first triangle number to have over five hundred divisors?

問 12 「高度整除三角数」

三角数の数列は自然数の和で表わされ, 7番目の三角数は 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28 である. 三角数の最初の10項は:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

となる.

最初の7項について, その約数を列挙すると, 以下のとおり.

1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28

これから, 7番目の三角数である28は, 5個より多く約数をもつ最初の三角数であることが分かる.

では, 500個より多く約数をもつ最初の三角数はいくつか.

struct TriangleNumber {
    _nth: u64,
    _primes: Vec<u64>,
    _num_div_even: u64,
    _num_div_odd: u64,
}

trait Divisors {
    fn number_of_divisors(&self) -> u64;
}

impl TriangleNumber {
    fn new() -> Self {
        Self {
            _nth: 3,
            _num_div_even: 2,
            _num_div_odd: 2,
            _primes: vec![2, 3],
        }
    }
    fn num(&self) -> u64 {
        self._nth * (self._nth + 1) / 2
    }
    fn _divide_fully(&self, n: &mut u64, d: u64, side: &mut u64, count: &mut u64) {
        if *n % d != 0 {
            return;
        }
        let mut exp = 0u64;
        while {
            *n /= d;
            exp += 1;
            *n % d == 0
        } {}
        *side = (*n as f64).sqrt() as u64;
        *count *= exp + 1;
    }
    fn _num_of_divisors(&mut self, mut n: u64) -> u64 {
        let mut count = 1u64;
        let mut side = (n as f64).sqrt() as u64;
        for p in &self._primes {
            if p > side || n == 1 {
                break;
            }
            self._divide_fully(&mut n, p, &mut side, &mut count);
        }
        if n != 1 {
            count *= 2;
            self._primes.push(n);
        }
        count
    }
    fn increment(&mut self) {
        self._nth += 1;
        if self._nth % 2 == 0 {
            self._num_div_odd = self._num_of_divisors(self._nth + 1);
        } else {
            self._num_div_even = self._num_of_divisors((self._nth + 1) / 2);
        }
    }
}

impl Divisors for TriangleNumber {
    fn number_of_divisors(&self) -> u64 {
        self._num_div_even * self._num_div_odd
    }
}

fn main() {
    let mut triangle_number = TriangleNumber::new();
    while triangle_number.number_of_divisors() <= 500 {
        triangle_number.increment();
    }
    let ans = triangle_number.num();

    println!("{}", ans);
    assert_eq!(ans, 76576500);
}
Problem 13 "Large sum"

Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.

37107287533902102798797998220837590246510135740250
46376937677490009712648124896970078050417018260538
74324986199524741059474233309513058123726617309629
91942213363574161572522430563301811072406154908250
23067588207539346171171980310421047513778063246676
89261670696623633820136378418383684178734361726757
28112879812849979408065481931592621691275889832738
44274228917432520321923589422876796487670272189318
47451445736001306439091167216856844588711603153276
70386486105843025439939619828917593665686757934951
62176457141856560629502157223196586755079324193331
64906352462741904929101432445813822663347944758178
92575867718337217661963751590579239728245598838407
58203565325359399008402633568948830189458628227828
80181199384826282014278194139940567587151170094390
35398664372827112653829987240784473053190104293586
86515506006295864861532075273371959191420517255829
71693888707715466499115593487603532921714970056938
54370070576826684624621495650076471787294438377604
53282654108756828443191190634694037855217779295145
36123272525000296071075082563815656710885258350721
45876576172410976447339110607218265236877223636045
17423706905851860660448207621209813287860733969412
81142660418086830619328460811191061556940512689692
51934325451728388641918047049293215058642563049483
62467221648435076201727918039944693004732956340691
15732444386908125794514089057706229429197107928209
55037687525678773091862540744969844508330393682126
18336384825330154686196124348767681297534375946515
80386287592878490201521685554828717201219257766954
78182833757993103614740356856449095527097864797581
16726320100436897842553539920931837441497806860984
48403098129077791799088218795327364475675590848030
87086987551392711854517078544161852424320693150332
59959406895756536782107074926966537676326235447210
69793950679652694742597709739166693763042633987085
41052684708299085211399427365734116182760315001271
65378607361501080857009149939512557028198746004375
35829035317434717326932123578154982629742552737307
94953759765105305946966067683156574377167401875275
88902802571733229619176668713819931811048770190271
25267680276078003013678680992525463401061632866526
36270218540497705585629946580636237993140746255962
24074486908231174977792365466257246923322810917141
91430288197103288597806669760892938638285025333403
34413065578016127815921815005561868836468420090470
23053081172816430487623791969842487255036638784583
11487696932154902810424020138335124462181441773470
63783299490636259666498587618221225225512486764533
67720186971698544312419572409913959008952310058822
95548255300263520781532296796249481641953868218774
76085327132285723110424803456124867697064507995236
37774242535411291684276865538926205024910326572967
23701913275725675285653248258265463092207058596522
29798860272258331913126375147341994889534765745501
18495701454879288984856827726077713721403798879715
38298203783031473527721580348144513491373226651381
34829543829199918180278916522431027392251122869539
40957953066405232632538044100059654939159879593635
29746152185502371307642255121183693803580388584903
41698116222072977186158236678424689157993532961922
62467957194401269043877107275048102390895523597457
23189706772547915061505504953922979530901129967519
86188088225875314529584099251203829009407770775672
11306739708304724483816533873502340845647058077308
82959174767140363198008187129011875491310547126581
97623331044818386269515456334926366572897563400500
42846280183517070527831839425882145521227251250327
55121603546981200581762165212827652751691296897789
32238195734329339946437501907836945765883352399886
75506164965184775180738168837861091527357929701337
62177842752192623401942399639168044983993173312731
32924185707147349566916674687634660915035914677504
99518671430235219628894890102423325116913619626622
73267460800591547471830798392868535206946944540724
76841822524674417161514036427982273348055556214818
97142617910342598647204516893989422179826088076852
87783646182799346313767754307809363333018982642090
10848802521674670883215120185883543223812876952786
71329612474782464538636993009049310363619763878039
62184073572399794223406235393808339651327408011116
66627891981488087797941876876144230030984490851411
60661826293682836764744779239180335110989069790714
85786944089552990653640447425576083659976645795096
66024396409905389607120198219976047599490197230297
64913982680032973156037120041377903785566085089252
16730939319872750275468906903707539413042652315011
94809377245048795150954100921645863754710598436791
78639167021187492431995700641917969777599028300699
15368713711936614952811305876380278410754449733078
40789923115535562561142322423255033685442488917353
44889911501440648020369068063960672322193204149535
41503128880339536053299340368006977710650566631954
81234880673210146739058568557934581403627822703280
82616570773948327592232845941706525094512325230608
22918802058777319719839450180888072429661980811197
77158542502016545090413245809786882778948721859617
72107838435069186155435662884062257473692284509516
20849603980134001723930671666823555245252804609722
53503534226472524250874054075591789781264330331690

問 13 「大きな数の足し算」

以下の50桁の数字100個の合計の上から10桁を求めなさい。


Go to 2. Variable-size input solution

1. Fixed-size input solution

fn main() {
    let input_digits = 50usize;
    let container_digits = 10usize;
    let overflow_threshold = 10u64.pow(container_digits as u32);

    let mut sum = 0u64;
    let mut carry = 0u64;
    for i in 0..input_digits / container_digits {
        let chunk_begin = input_digits - container_digits * (i + 1);
        let chunk_end = input_digits - container_digits * i;
        sum = FIFTY_DIGIT_NUMBERS
            .iter()
            .map(|&s| &s[chunk_begin..chunk_end])
            .map(|s| s.parse::<u64>().unwrap())
            .sum::<u64>()
            + carry;
        carry = sum / overflow_threshold;
    }

    let display_threshold = 10u64.pow(10);
    while sum >= display_threshold {
        sum /= 10;
    }

    println!("{}", sum);
    assert_eq!(sum, 5537376230);
}

const FIFTY_DIGIT_NUMBERS: [&str; 100] = [
    "37107287533902102798797998220837590246510135740250",
    "46376937677490009712648124896970078050417018260538",
    "74324986199524741059474233309513058123726617309629",
    "91942213363574161572522430563301811072406154908250",
    "23067588207539346171171980310421047513778063246676",
    "89261670696623633820136378418383684178734361726757",
    "28112879812849979408065481931592621691275889832738",
    "44274228917432520321923589422876796487670272189318",
    "47451445736001306439091167216856844588711603153276",
    "70386486105843025439939619828917593665686757934951",
    "62176457141856560629502157223196586755079324193331",
    "64906352462741904929101432445813822663347944758178",
    "92575867718337217661963751590579239728245598838407",
    "58203565325359399008402633568948830189458628227828",
    "80181199384826282014278194139940567587151170094390",
    "35398664372827112653829987240784473053190104293586",
    "86515506006295864861532075273371959191420517255829",
    "71693888707715466499115593487603532921714970056938",
    "54370070576826684624621495650076471787294438377604",
    "53282654108756828443191190634694037855217779295145",
    "36123272525000296071075082563815656710885258350721",
    "45876576172410976447339110607218265236877223636045",
    "17423706905851860660448207621209813287860733969412",
    "81142660418086830619328460811191061556940512689692",
    "51934325451728388641918047049293215058642563049483",
    "62467221648435076201727918039944693004732956340691",
    "15732444386908125794514089057706229429197107928209",
    "55037687525678773091862540744969844508330393682126",
    "18336384825330154686196124348767681297534375946515",
    "80386287592878490201521685554828717201219257766954",
    "78182833757993103614740356856449095527097864797581",
    "16726320100436897842553539920931837441497806860984",
    "48403098129077791799088218795327364475675590848030",
    "87086987551392711854517078544161852424320693150332",
    "59959406895756536782107074926966537676326235447210",
    "69793950679652694742597709739166693763042633987085",
    "41052684708299085211399427365734116182760315001271",
    "65378607361501080857009149939512557028198746004375",
    "35829035317434717326932123578154982629742552737307",
    "94953759765105305946966067683156574377167401875275",
    "88902802571733229619176668713819931811048770190271",
    "25267680276078003013678680992525463401061632866526",
    "36270218540497705585629946580636237993140746255962",
    "24074486908231174977792365466257246923322810917141",
    "91430288197103288597806669760892938638285025333403",
    "34413065578016127815921815005561868836468420090470",
    "23053081172816430487623791969842487255036638784583",
    "11487696932154902810424020138335124462181441773470",
    "63783299490636259666498587618221225225512486764533",
    "67720186971698544312419572409913959008952310058822",
    "95548255300263520781532296796249481641953868218774",
    "76085327132285723110424803456124867697064507995236",
    "37774242535411291684276865538926205024910326572967",
    "23701913275725675285653248258265463092207058596522",
    "29798860272258331913126375147341994889534765745501",
    "18495701454879288984856827726077713721403798879715",
    "38298203783031473527721580348144513491373226651381",
    "34829543829199918180278916522431027392251122869539",
    "40957953066405232632538044100059654939159879593635",
    "29746152185502371307642255121183693803580388584903",
    "41698116222072977186158236678424689157993532961922",
    "62467957194401269043877107275048102390895523597457",
    "23189706772547915061505504953922979530901129967519",
    "86188088225875314529584099251203829009407770775672",
    "11306739708304724483816533873502340845647058077308",
    "82959174767140363198008187129011875491310547126581",
    "97623331044818386269515456334926366572897563400500",
    "42846280183517070527831839425882145521227251250327",
    "55121603546981200581762165212827652751691296897789",
    "32238195734329339946437501907836945765883352399886",
    "75506164965184775180738168837861091527357929701337",
    "62177842752192623401942399639168044983993173312731",
    "32924185707147349566916674687634660915035914677504",
    "99518671430235219628894890102423325116913619626622",
    "73267460800591547471830798392868535206946944540724",
    "76841822524674417161514036427982273348055556214818",
    "97142617910342598647204516893989422179826088076852",
    "87783646182799346313767754307809363333018982642090",
    "10848802521674670883215120185883543223812876952786",
    "71329612474782464538636993009049310363619763878039",
    "62184073572399794223406235393808339651327408011116",
    "66627891981488087797941876876144230030984490851411",
    "60661826293682836764744779239180335110989069790714",
    "85786944089552990653640447425576083659976645795096",
    "66024396409905389607120198219976047599490197230297",
    "64913982680032973156037120041377903785566085089252",
    "16730939319872750275468906903707539413042652315011",
    "94809377245048795150954100921645863754710598436791",
    "78639167021187492431995700641917969777599028300699",
    "15368713711936614952811305876380278410754449733078",
    "40789923115535562561142322423255033685442488917353",
    "44889911501440648020369068063960672322193204149535",
    "41503128880339536053299340368006977710650566631954",
    "81234880673210146739058568557934581403627822703280",
    "82616570773948327592232845941706525094512325230608",
    "22918802058777319719839450180888072429661980811197",
    "77158542502016545090413245809786882778948721859617",
    "72107838435069186155435662884062257473692284509516",
    "20849603980134001723930671666823555245252804609722",
    "53503534226472524250874054075591789781264330331690",
];

Go to 1. Fixed-size input solution

2. Variable-size input solution

struct BigNum {
    a: Vec<u64>,
}

fn paging(b: &str, page: usize, unit: usize) -> Option<&str> {
    let len = b.len();
    if len <= unit && page == 0 {
        return Some(b);
    } else if len <= unit && page > 0 {
        return None;
    }
    let end = len as isize - page as isize * unit as isize;
    if end <= 0 {
        return None;
    }
    let begin = end - unit as isize;
    if begin < 0 {
        Some(&b[0..end as usize])
    } else {
        Some(&b[begin as usize..end as usize])
    }
}

impl BigNum {
    const TEN_MIL: u64 = 10_000_000_000;
    const TEN_MIL_STR_CAP: usize = 10;
    fn new() -> Self {
        Self { a: vec![] }
    }
    fn merge(&mut self, page: usize, n: u64, carry: &mut u64) {
        if self.a.get(page).is_none() {
            self.a.push(0u64)
        }
        if let Some(con) = self.a.get_mut(page) {
            *con += n + *carry;
            if *con < Self::TEN_MIL {
                *carry = 0;
                return;
            }
            *carry = 1;
            *con -= Self::TEN_MIL;
        }
    }
    fn add(&mut self, b: &str) {
        let mut p = 0usize;
        let mut carry = 0u64;
        while let Some(s) = paging(&b, p, Self::TEN_MIL_STR_CAP) {
            let n = s.parse::<u64>().unwrap();
            self.merge(p, n, &mut carry);
            p += 1;
        }
        while carry != 0 {
            self.merge(p, 0, &mut carry);
            p += 1;
        }
    }
    fn head(&self, digits: u8) -> u64 {
        assert!(digits <= 10);
        let mut head = 0u64;
        for p in (0..self.a.len()).rev() {
            if let Some(&con) = self.a.get(p) {
                if head > u64::MAX / Self::TEN_MIL {
                    break;
                }
                head *= Self::TEN_MIL;
                head += con;
            }
        }
        let display_threshold = 10u64.pow(digits as u32);
        while head >= display_threshold {
            head /= 10;
        }
        head
    }
}

fn main() {
    let mut big_num = BigNum::new();
    for &b in FIFTY_DIGIT_NUMBERS.iter() {
        big_num.add(b);
    }
    let ans = big_num.head(10);

    println!("{}", ans);
    assert_eq!(ans, 5537376230);

    {
        let mut a = BigNum::new();
        for &b in vec!["5", "48", "125"].iter() {
            a.add(b);
        }
        assert_eq!(a.head(10), 178);
    }
    {
        let mut a = BigNum::new();
        let v = vec![
            "9999999999",
            "99999999999999999999",
            "40005484537376233",
            "3",
            "5537376230",
            "40000000000000"
        ];
        for &b in v.iter() {
            a.add(b);
        }
        assert_eq!(a.head(10), 1000400455);
    }
    {
        let mut a = BigNum::new();
        a.add(&"99999999999999999999");
        assert_eq!(a.head(10), 9999999999);
    }
}

const FIFTY_DIGIT_NUMBERS: [&str; 100] = [
    "37107287533902102798797998220837590246510135740250",
    "46376937677490009712648124896970078050417018260538",
    "74324986199524741059474233309513058123726617309629",
    "91942213363574161572522430563301811072406154908250",
    "23067588207539346171171980310421047513778063246676",
    "89261670696623633820136378418383684178734361726757",
    "28112879812849979408065481931592621691275889832738",
    "44274228917432520321923589422876796487670272189318",
    "47451445736001306439091167216856844588711603153276",
    "70386486105843025439939619828917593665686757934951",
    "62176457141856560629502157223196586755079324193331",
    "64906352462741904929101432445813822663347944758178",
    "92575867718337217661963751590579239728245598838407",
    "58203565325359399008402633568948830189458628227828",
    "80181199384826282014278194139940567587151170094390",
    "35398664372827112653829987240784473053190104293586",
    "86515506006295864861532075273371959191420517255829",
    "71693888707715466499115593487603532921714970056938",
    "54370070576826684624621495650076471787294438377604",
    "53282654108756828443191190634694037855217779295145",
    "36123272525000296071075082563815656710885258350721",
    "45876576172410976447339110607218265236877223636045",
    "17423706905851860660448207621209813287860733969412",
    "81142660418086830619328460811191061556940512689692",
    "51934325451728388641918047049293215058642563049483",
    "62467221648435076201727918039944693004732956340691",
    "15732444386908125794514089057706229429197107928209",
    "55037687525678773091862540744969844508330393682126",
    "18336384825330154686196124348767681297534375946515",
    "80386287592878490201521685554828717201219257766954",
    "78182833757993103614740356856449095527097864797581",
    "16726320100436897842553539920931837441497806860984",
    "48403098129077791799088218795327364475675590848030",
    "87086987551392711854517078544161852424320693150332",
    "59959406895756536782107074926966537676326235447210",
    "69793950679652694742597709739166693763042633987085",
    "41052684708299085211399427365734116182760315001271",
    "65378607361501080857009149939512557028198746004375",
    "35829035317434717326932123578154982629742552737307",
    "94953759765105305946966067683156574377167401875275",
    "88902802571733229619176668713819931811048770190271",
    "25267680276078003013678680992525463401061632866526",
    "36270218540497705585629946580636237993140746255962",
    "24074486908231174977792365466257246923322810917141",
    "91430288197103288597806669760892938638285025333403",
    "34413065578016127815921815005561868836468420090470",
    "23053081172816430487623791969842487255036638784583",
    "11487696932154902810424020138335124462181441773470",
    "63783299490636259666498587618221225225512486764533",
    "67720186971698544312419572409913959008952310058822",
    "95548255300263520781532296796249481641953868218774",
    "76085327132285723110424803456124867697064507995236",
    "37774242535411291684276865538926205024910326572967",
    "23701913275725675285653248258265463092207058596522",
    "29798860272258331913126375147341994889534765745501",
    "18495701454879288984856827726077713721403798879715",
    "38298203783031473527721580348144513491373226651381",
    "34829543829199918180278916522431027392251122869539",
    "40957953066405232632538044100059654939159879593635",
    "29746152185502371307642255121183693803580388584903",
    "41698116222072977186158236678424689157993532961922",
    "62467957194401269043877107275048102390895523597457",
    "23189706772547915061505504953922979530901129967519",
    "86188088225875314529584099251203829009407770775672",
    "11306739708304724483816533873502340845647058077308",
    "82959174767140363198008187129011875491310547126581",
    "97623331044818386269515456334926366572897563400500",
    "42846280183517070527831839425882145521227251250327",
    "55121603546981200581762165212827652751691296897789",
    "32238195734329339946437501907836945765883352399886",
    "75506164965184775180738168837861091527357929701337",
    "62177842752192623401942399639168044983993173312731",
    "32924185707147349566916674687634660915035914677504",
    "99518671430235219628894890102423325116913619626622",
    "73267460800591547471830798392868535206946944540724",
    "76841822524674417161514036427982273348055556214818",
    "97142617910342598647204516893989422179826088076852",
    "87783646182799346313767754307809363333018982642090",
    "10848802521674670883215120185883543223812876952786",
    "71329612474782464538636993009049310363619763878039",
    "62184073572399794223406235393808339651327408011116",
    "66627891981488087797941876876144230030984490851411",
    "60661826293682836764744779239180335110989069790714",
    "85786944089552990653640447425576083659976645795096",
    "66024396409905389607120198219976047599490197230297",
    "64913982680032973156037120041377903785566085089252",
    "16730939319872750275468906903707539413042652315011",
    "94809377245048795150954100921645863754710598436791",
    "78639167021187492431995700641917969777599028300699",
    "15368713711936614952811305876380278410754449733078",
    "40789923115535562561142322423255033685442488917353",
    "44889911501440648020369068063960672322193204149535",
    "41503128880339536053299340368006977710650566631954",
    "81234880673210146739058568557934581403627822703280",
    "82616570773948327592232845941706525094512325230608",
    "22918802058777319719839450180888072429661980811197",
    "77158542502016545090413245809786882778948721859617",
    "72107838435069186155435662884062257473692284509516",
    "20849603980134001723930671666823555245252804609722",
    "53503534226472524250874054075591789781264330331690",
];
Problem 14 "Longest Collatz sequence"

The following iterative sequence is defined for the set of positive integers:

nn/2 (n is even)
n → 3n + 1 (n is odd)

Using the rule above and starting with 13, we generate the following sequence:

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.

Which starting number, under one million, produces the longest chain?

NOTE: Once the chain starts the terms are allowed to go above one million.

問 14 「最長のコラッツ数列」

正の整数に以下の式で繰り返し生成する数列を定義する.

nn/2 (n が偶数)
n → 3n + 1 (n が奇数)

13からはじめるとこの数列は以下のようになる.

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

13から1まで10個の項になる. この数列はどのような数字からはじめても最終的には 1 になると考えられているが, まだそのことは証明されていない(コラッツ問題)

さて, 100万未満の数字の中でどの数字からはじめれば最長の数列を生成するか.

''注意'': 数列の途中で100万以上になってもよい

struct Position {
    initial_number: u64,
    number_of_steps: u32,
}

struct Collatz {
    init_num: u64,
    next: Option<u64>,
    step_accum: u32,
    cache: Vec<u32>,
    max: Position,
}

impl Collatz {
    fn update_records(&mut self) {
        if let Some(s) = self.cache.get_mut(self.init_num as usize) {
            *s = self.step_accum;
        }
        if self.max.number_of_steps < self.step_accum {
            self.max.number_of_steps = self.step_accum;
            self.max.initial_number = self.init_num;
        }
    }
    fn move_along(&mut self) -> Option<u64> {
        let n = self.next?;
        if n == 1 {
            self.step_accum += 1;
            self.next = None;
            self.update_records();
            return self.next;
        }
        match self.cache.get(n as usize) {
            Some(r) if *r != 0 => {
                self.step_accum += 1 + *r;
                self.next = None;
                self.update_records();
                return self.next;
            }
            _ => (),
        }
        if n % 2 != 0 {
            self.step_accum += 2;
            self.next = Some((3 * n + 1) / 2);
            return self.next;
        }
        self.step_accum += 1;
        self.next = Some(n / 2);
        self.next
    }
    fn init_next(&mut self) {
        assert!(self.init_num > 1);
        self.next = if self.init_num % 2 == 0 {
            Some(self.init_num / 2)
        } else {
            Some(3 * self.init_num + 1)
        }
    }
}

fn main() {
    let mut c = Collatz {
        init_num: 0,
        next: None,
        step_accum: 0,
        cache: vec![0; 1_000_000],
        max: Position {
            initial_number: 1,
            number_of_steps: 0,
        },
    };

    for i in 500_000..1_000_000u64 {
        c.init_num = i;
        c.init_next();
        c.step_accum = 0;
        while c.move_along().is_some() {}
    }

    println!(
        "initial_number: {}, number_of_steps plus 1: {}",
        c.max.initial_number,
        c.max.number_of_steps + 1
    );
    assert_eq!(c.max.initial_number, 837799);
    assert_eq!(c.max.number_of_steps + 1, 525);
}
Problem 15 "Lattice paths"

Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 routes to the bottom right corner.

How many such routes are there through a 20×20 grid?

問 15 「格子経路」

2×2 のマス目の左上からスタートした場合, 引き返しなしで右下にいくルートは 6 つある.

では, 20×20 のマス目ではいくつのルートがあるか.

struct Permutation {
    numerator: u8,
    denominator: u8,
}

impl Permutation {
    fn num(&self) -> u128 {
        let mut acc = 1u128;
        for i in self.denominator + 1..=self.numerator {
            acc *= i as u128;
        }
        acc
    }
}

struct Grid {
    width: u8,
    height: u8,
}

fn factorial(n: u8) -> u128 {
    match n {
        0 | 1 => 1,
        _ => factorial(n - 1) * n as u128,
    }
}

impl Grid {
    fn routes(&self) -> u64 {
        let a = Permutation {
            numerator: self.width + self.height,
            denominator: self.width,
        }
        .num();
        let b = factorial(self.height);
        (a / b) as u64
    }
}

fn main() {
    let r = Grid {
        width: 20,
        height: 20,
    }
    .routes();

    println!("{}", r);
    assert_eq!(r, 137846528820);
}

fn main() {
    let mut lattice = [[0u64; 22]; 22];
    lattice[1][1] = 1;
    for y in 1..lattice.len() {
        for x in 1..lattice.len() {
            lattice[y][x] += lattice[y - 1][x] + lattice[y][x - 1];
        }
    }
    let r = lattice[21][21];

    println!("{}", r);
    assert_eq!(r, 137846528820);
}

struct Combination {
    n: f64,
    k: f64,
}

impl Combination {
    fn _num(&self, n: f64, k: f64) -> f64 {
        if k == 1f64 {
            return n;
        }
        if k == 0f64 {
            return 1f64;
        }
        let prev = self._num(n, k - 1f64);
        prev * (n - k + 1f64) / k
    }
    fn num(&self) -> f64 {
        self._num(self.n, self.k)
    }
}

struct Grid {
    width: u8,
    height: u8,
}

impl Grid {
    fn routes(&self) -> u64 {
        Combination{
            n: (self.width + self.height) as f64,
            k: self.width as f64,
        }
        .num().ceil() as u64
    }
}

fn main() {
    let r = Grid {
        width: 20,
        height: 20,
    }
    .routes();

    println!("{}", r);
    assert_eq!(r, 137846528820);
}

struct Combination {
    n: f64,
    k: f64,
}

impl Combination {
    fn num(&self) -> f64 {
        assert!(self.n == 2f64 * self.k);
        (1..=self.k as usize)
            .map(|x| x as f64)
            .map(|x| (self.k + x) / x)
            .product::<f64>()
    }
}

struct Grid {
    width: u8,
    height: u8,
}

impl Grid {
    fn routes(&self) -> u64 {
        Combination{
            n: (self.width + self.height) as f64,
            k: self.width as f64,
        }
        .num().ceil() as u64
    }
}

fn main() {
    let r = Grid {
        width: 20,
        height: 20,
    }
    .routes();

    println!("{}", r);
    assert_eq!(r, 137846528820);
}

fn main() {
    let mut b = 1u64;
    for i in 1..=20 {
        b *= i;
    }
    let mut ab = 1f64 / b as f64;
    for i in 21..=40 {
        ab *= i as f64;
    }
    println!("{}", ab);
    assert_eq!(ab.ceil() as u64, 137846528820);
}
fn main() {
    let b = 1f64 / (1..=20).product::<u64>() as f64;
    let ab = (21..=40).fold(b, |p, i| p * i as f64);
    println!("{}", ab);
    assert_eq!(ab.ceil() as u64, 137846528820);
}
Problem 16 "Power digit sum"

215 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26.

What is the sum of the digits of the number 21000?

問 16 「各位の数字の和」

\( 2^{15} \) = 32768 であり, 各位の数字の和は 3 + 2 + 7 + 6 + 8 = 26 となる.

同様にして, \( 2^{1000} \) の各位の数字の和を求めよ.

struct BigNum {
    v: Vec<u64>,
}

impl BigNum {
    const TEN_MIL: u64 = 10_000_000_000;
    fn double(&mut self) {
        let mut carry = 0u64;
        for con in self.v.iter_mut() {
            *con *= 2;
            *con += carry;
            if *con < Self::TEN_MIL {
                carry = 0;
                continue;
            }
            carry = 1;
            *con -= Self::TEN_MIL;
        }
        if carry != 0 {
            self.v.push(1u64);
        }
    }
    fn sum_of_digits(&self) -> u32 {
        let mut sum = 0u32;
        for &con in &self.v {
            let mut t = con;
            while t > 0 {
                sum += (t % 10) as u32;
                t /= 10;
            }
        }
        sum
    }
}

fn main() {
    let mut n = BigNum { v: vec![1] };
    for _ in 0..1000 {
        n.double();
    }
    let ans = n.sum_of_digits();

    println!("{}", ans);
    assert_eq!(ans, 1366);
}
Problem 17 "Number letter counts"

If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.

If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?


NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage.

問 17 「数字の文字数」

1 から 5 までの数字を英単語で書けば one, two, three, four, five であり, 全部で 3 + 3 + 5 + 4 + 4 = 19 の文字が使われている.

では 1 から 1000 (one thousand) までの数字をすべて英単語で書けば, 全部で何文字になるか.

''注'': 空白文字やハイフンを数えないこと. 例えば, 342 (three hundred and forty-two) は 23 文字, 115 (one hundred and fifteen) は20文字と数える. なお, "and" を使用するのは英国の慣習.

const ZERO_TO_19: [&str; 20] = [
    "",
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
    "seven",
    "eight",
    "nine",
    "ten",
    "eleven",
    "twelve",
    "thirteen",
    "fourteen",
    "fifteen",
    "sixteen",
    "seventeen",
    "eighteen",
    "nineteen",
];

const ZERO_TO_90: [&str; 10] = [
    "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety",
];

fn count_words(i: usize) -> u32 {
    match i {
        0..=19 => ZERO_TO_19[i].len() as u32,
        20..=99 => {
            let p1 = i % 10;
            let p2 = i / 10;
            (ZERO_TO_90[p2].len() + ZERO_TO_19[p1].len()) as u32
        }
        _ if i % 100 == 0 && i != 1000 => {
            let d = i / 100;
            (ZERO_TO_19[d].len() + "hundred".len()) as u32
        }
        101..=999 => {
            let p3 = i / 100;
            let p2p1 = i - p3 * 100;
            (ZERO_TO_19[p3].len() + "hundredand".len()) as u32 + count_words(p2p1)
        }
        1000 => ("onethousand".len()) as u32,
        _ => 0,
    }
}

fn main() {
    let mut sum = 0u32;
    for i in 1..=1000 {
        sum += count_words(i);
    }

    println!("{}", sum);
    assert_eq!(sum, 21124);
}
Problem 18 "Maximum path sum I"

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

3
7 4
2 4 6
8 5 9 3

That is, 3 + 7 + 4 + 9 = 23.

Find the maximum total from top to bottom of the triangle below:

75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23

NOTE: As there are only 16384 routes, it is possible to solve this problem by trying every route. However, Problem 67, is the same challenge with a triangle containing one-hundred rows; it cannot be solved by brute force, and requires a clever method! ;o)

問 「最大経路の和 その1」

以下の三角形の頂点から下の行の隣接する数字を通って下まで移動するとき, その数値の和の最大値は23になる.

この例では 3 + 7 + 4 + 9 = 23.

以下の三角形を頂点から下まで移動するとき, その最大の和を求めよ.

''注:'' ここではたかだか 16384 通りのルートしかないので, すべてのパターンを試すこともできる. Problem 67 は同じ問題だが100行あるので, 総当りでは解けない. もっと賢い方法が必要である.

fn main() {
    let mut triangle: Vec<Vec<u16>> = vec![
        vec![75],
        vec![95, 64],
        vec![17, 47, 82],
        vec![18, 35, 87, 10],
        vec![20, 4, 82, 47, 65],
        vec![19, 1, 23, 75, 3, 34],
        vec![88, 2, 77, 73, 7, 63, 67],
        vec![99, 65, 4, 28, 6, 16, 70, 92],
        vec![41, 41, 26, 56, 83, 40, 80, 70, 33],
        vec![41, 48, 72, 33, 47, 32, 37, 16, 94, 29],
        vec![53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14],
        vec![70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57],
        vec![91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48],
        vec![63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31],
        vec![4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23],
    ];
    triangle.push(vec![0; triangle.last().unwrap().len() + 1]);
    for y in (0..triangle.len() - 1).rev() {
        for x in 0..triangle[y].len() {
            let a = triangle[y + 1][x];
            let b = triangle[y + 1][x + 1];
            triangle[y][x] += std::cmp::max(a, b);
        }
    }
    let sum = triangle[0][0];

    println!("{}", sum);
    assert_eq!(sum, 1074);
}
Problem 19 "Counting Sundays"

You are given the following information, but you may prefer to do some research for yourself.

  • 1 Jan 1900 was a Monday.
  • Thirty days has September,
    April, June and November.
    All the rest have thirty-one,
    Saving February alone,
    Which has twenty-eight, rain or shine.
    And on leap years, twenty-nine.
  • A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.

How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?

問 19 「日曜日の数え上げ」

次の情報が与えられている.

  • 1900年1月1日は月曜日である.

  • 9月, 4月, 6月, 11月は30日まであり, 2月を除く他の月は31日まである.

  • 2月は28日まであるが, うるう年のときは29日である.

  • うるう年は西暦が4で割り切れる年に起こる. しかし, 西暦が400で割り切れず100で割り切れる年はうるう年でない.

20世紀(1901年1月1日から2000年12月31日)中に月の初めが日曜日になるのは何回あるか?


https://drive.google.com/file/d/1nu4YU5BIEr_aZi8Ne0QbwkFOYDg6l6Fd/view

fn length_of_february(year: u16) -> u8 {
    if (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 {
        29
    } else {
        28
    }
}

struct FirstDayOfMonth {
    year: u16,
    month: u8,
    day_count: u64,
    sunday_count: u32,
}

impl FirstDayOfMonth {
    fn new() -> Self {
        Self {
            year: 1900,
            month: 1,
            day_count: 0,
            sunday_count: 0,
        }
    }
    fn is_sunday(&self) -> bool {
        self.day_count % 7 == 6
    }
    fn next_month(&mut self) {
        self.day_count += match self.month {
            2 => length_of_february(self.year) as u64,
            4 | 6 | 9 | 11 => 30,
            _ => 31,
        };
        if self.month == 12 {
            self.year += 1;
            self.month = 1;
        } else {
            self.month += 1;
        }
        if self.year != 1900 && self.is_sunday() {
            self.sunday_count += 1;
        }
    }
}

fn main() {
    let mut cal = FirstDayOfMonth::new();
    while !(cal.year == 2000 && cal.month == 12) {
        cal.next_month();
    }
    let sum = cal.sunday_count;

    println!("{}", sum);
    assert_eq!(sum, 171);
}

#[derive(PartialEq)]
enum Weekday {
    Mon,
    Tue,
    Wed,
    Thu,
    Fri,
    Sat,
    Sun,
}

fn zeller_congruence(mut y: u32, mut m: u32, d: u32) -> Weekday {
    if m == 1 || m == 2 {
        m += 12;
        y -= 1;
    }
    let yd = y / 100;
    let ym = y % 100;
    match (d + (26 * (m + 1)) / 10 + ym + ym / 4 + yd / 4 + 5 * yd) % 7 {
        0 => Weekday::Sat,
        1 => Weekday::Sun,
        2 => Weekday::Mon,
        3 => Weekday::Tue,
        4 => Weekday::Wed,
        5 => Weekday::Thu,
        6 => Weekday::Fri,
        _ => panic!(),
    }
}

fn main() {
    let mut sum = 0u32;
    for y in 1901u32..=2000 {
        for m in 1u32..=12 {
            let weekday = zeller_congruence(y, m, 1);
            if weekday == Weekday::Sun {
                sum += 1;
            }
        }
    }

    println!("{}", sum);
    assert_eq!(sum, 171);
}

Problem 20 "Factorial digit sum"

n! means n × (n − 1) × ... × 3 × 2 × 1

For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800,
and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.

Find the sum of the digits in the number 100!

問 20 「各位の数字の和 2」

n! は n × (n − 1) × ... × 3 × 2 × 1

例えば, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800 となる.

この数の各桁の合計は 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27 である.

では, 100! の各位の数字の和を求めよ.

struct BigNum {
    v: Vec<u64>,
}

impl BigNum {
    const TEN_MIL: u64 = 10_000_000_000;
    fn factorial(&mut self) {
        assert!(self.v.len() == 1);
        let up = self.v[0];
        assert!(((u64::MAX as f32 - Self::TEN_MIL as f32) / Self::TEN_MIL as f32) > (up as f32));
        for b in 2..up {
            self._multiply(b);
        }
    }
    fn _multiply(&mut self, b: u64) {
        let mut carry = 0u64;
        for con in self.v.iter_mut() {
            *con *= b;
            *con += carry;
            if *con < Self::TEN_MIL {
                carry = 0;
                continue;
            }
            carry = *con / Self::TEN_MIL;
            *con -= carry * Self::TEN_MIL;
        }
        if carry != 0 {
            self.v.push(carry);
        }
    }
    fn sum_of_digits(&self) -> u32 {
        let mut sum = 0u32;
        for &con in &self.v {
            let mut t = con;
            while t > 0 {
                sum += (t % 10) as u32;
                t /= 10;
            }
        }
        sum
    }
}

fn main() {
    let mut a = BigNum { v: vec![100u64] };
    a.factorial();
    let sum = a.sum_of_digits();

    println!("{}", sum);
    assert_eq!(sum, 648);
}
Problem 21 "Amicable numbers"

Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n).
If d(a) = b and d(b) = a, where ab, then a and b are an amicable pair and each of a and b are called amicable numbers.

For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.

Evaluate the sum of all the amicable numbers under 10000.

問 21 「友愛数」

d(\(n\)) を \(n\) の真の約数の和と定義する. (真の約数とは \(n\) 以外の約数のことである. )

もし, d(\(a\)) = \(b\); かつ d(\(b\)) = \(a\); (\(a\) ≠ \(b\) のとき) を満たすとき, \(a\) と \(b\) は友愛数(親和数)であるという.

例えば, 220 の約数は 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110 なので d(220) = 284 である.

また, 284 の約数は 1, 2, 4, 71, 142 なので d(284) = 220 である.

それでは10000未満の友愛数の和を求めよ.

struct AmicableNumberScanner {
    below: u32,
    _primes: Vec<u32>,
    _aliquot_sum: Vec<u32>,
}

impl AmicableNumberScanner {
    fn new(below: u32) -> Self {
        Self {
            below: below,
            _primes: vec![2, 3],
            _aliquot_sum: vec![0u32; below as usize],
        }
    }
    fn _divide_fully(&self, n: &mut u32, d: u32, side: &mut u32, sum: &mut u32) {
        if *n % d != 0 {
            return;
        }
        let mut exp = 0u32;
        while {
            *n /= d;
            exp += 1;
            *n % d == 0
        } {}
        *side = (*n as f32).sqrt() as u32;
        *sum *= (d.pow(exp + 1) - 1) / (d - 1);
    }
    fn _sum_of_divisors(&mut self, mut n: u32) -> u32 {
        let mut side = (n as f32).sqrt() as u32;
        let mut sum = 1u32;
        for &p in &self._primes {
            if p > side || n == 1 {
                break;
            }
            self._divide_fully(&mut n, p, &mut side, &mut sum);
        }
        if n != 1 {
            sum *= (n * n - 1) / (n - 1);
            self._primes.push(n);
        }
        sum
    }
    fn pair_sum(&mut self) -> u32 {
        for n in 4..self.below {
            self._aliquot_sum[n as usize] = self._sum_of_divisors(n) - n;
        }
        let mut sum = 0u32;
        for (i, v) in &self._aliquot_sum.enumerate() {
            let vsize = *v as usize;
            if vsize >= self._aliquot_sum.len() {
                continue;
            }
            if vsize == i {
                continue;
            }
            if self._aliquot_sum[vsize] == i as u32 {
                sum += *v;
            }
        }
        sum
    }
}

fn main() {
    let sum = AmicableNumberScanner::new(10_000).pair_sum();

    println!("{}", sum);
    assert_eq!(sum, 31626);
}

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

fn rule_out(sieve: &mut Vec<bool>, prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn primes(below: u32) -> Vec<u32> {
    let mut primes: Vec<u32> = vec![2u32, 3u32];
    let mut sieve = vec![true; below as usize];
    let sqrt = (sieve.len() as f32).sqrt() as usize;
    let mut index = Index::new();
    while index.i <= sqrt {
        if sieve[index.i] {
            primes.push(index.i as u32);
            rule_out(&mut sieve, index.i);
        }
        index.increment();
    }
    while index.i < sieve.len() {
        if sieve[index.i] {
            primes.push(index.i as u32);
        }
        index.increment();
    }
    primes
}

struct AmicableNumberScanner {
    below: u32,
    _primes: Vec<u32>,
    _checked: Vec<bool>,
}

impl AmicableNumberScanner {
    fn new(below: u32) -> Self {
        Self {
            below: below,
            _primes: primes(below),
            _checked: vec![false; below as usize],
        }
    }
    fn _divide_fully(&self, n: &mut u32, d: u32, side: &mut u32, sum: &mut u32) {
        if *n % d != 0 {
            return;
        }
        let mut exp = 0u32;
        while {
            *n /= d;
            exp += 1;
            *n % d == 0
        } {}
        *side = (*n as f32).sqrt() as u32;
        *sum *= (d.pow(exp + 1) - 1) / (d - 1);
    }
    fn _sum_of_divisors(&mut self, mut n: u32) -> u32 {
        let mut side = (n as f32).sqrt() as u32;
        let mut sum = 1u32;
        for &p in self._primes.iter() {
            if p > side || n == 1 {
                break;
            }
            self._divide_fully(&mut n, p, &mut side, &mut sum);
        }
        if n != 1 {
            sum *= (n * n - 1) / (n - 1);
        }
        sum
    }
    fn pair_sum(&mut self) -> u32 {
        let mut pair_sum = 0u32;
        for a in 4..self.below {
            if self._checked[a as usize] {
                continue;
            }
            let sum = self._sum_of_divisors(a) - a;
            if sum <= a {
                continue;
            }
            if sum >= self.below {
                continue;
            }
            let b = self._sum_of_divisors(sum) - sum;
            self._checked[sum as usize] = true;
            if a == b {
                pair_sum += a + sum;
            }
        }
        pair_sum
    }
}

fn main() {
    let sum = AmicableNumberScanner::new(10_000).pair_sum();

    println!("{}", sum);
    assert_eq!(sum, 31626);
}
Problem 22 "Name scores"

Using names.txt, a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.

For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.

What is the total of all the name scores in the file?

問 22 「名前のスコア」

5000個以上の名前が書かれている46Kのテキストファイル p022_names.txt を用いる. まずアルファベット順にソートせよ.

のち, 各名前についてアルファベットに値を割り振り, リスト中の出現順の数と掛け合わせることで, 名前のスコアを計算する.

たとえば, リストがアルファベット順にソートされているとすると, COLINはリストの938番目にある. またCOLINは 3 + 15 + 12 + 9 + 14 = 53 という値を持つ. よってCOLINは 938 × 53 = 49714 というスコアを持つ.

ファイル中の全名前のスコアの合計を求めよ.

Because the original name list is very long, these examples have only a part of it.

1. Quick sort

fn median<'a>(vec: &[&'a str], a: usize, c: usize) -> &'a str {
    let b = (c - a) / 2;
    let (astr, bstr, cstr) = (vec[a], vec[b], vec[c]);
    if (cstr < astr && astr < bstr) || (bstr <= astr && astr < cstr) {
        astr
    } else if (astr < bstr && bstr < cstr) || (cstr < bstr && bstr <= astr) {
        bstr
    } else {
        cstr
    }
}

fn met(sinker_depth: usize, float_depth: usize) -> bool {
    sinker_depth >= float_depth
}

fn sink_fully(vec: &[&str], depth: &mut usize, blocker: &str) {
    while vec[*depth] < blocker {
        *depth += 1;
    }
}

fn float_fully(vec: &[&str], depth: &mut usize, blocker: &str) {
    while vec[*depth] > blocker {
        *depth -= 1;
    }
}

fn break_through(vec: &mut [&str], sinker_depth: &mut usize, float_depth: &mut usize) {
    vec.swap(*sinker_depth, *float_depth);
    *sinker_depth += 1;
    *float_depth -= 1;
}

fn release(vec: &mut [&str], sinker0: usize, float0: usize) {
    if met(sinker0, float0) {
        return;
    }
    match float0 - sinker0 {
        1 => {
            if vec[sinker0] > vec[sinker0 + 1] {
                vec.swap(sinker0, sinker0 + 1);
            }
            return;
        }
        2 => {
            if vec[sinker0] > vec[sinker0 + 1] {
                vec.swap(sinker0, sinker0 + 1);
            }
            if vec[sinker0 + 1] > vec[sinker0 + 2] {
                vec.swap(sinker0 + 1, sinker0 + 2);
            }
            if vec[sinker0] > vec[sinker0 + 1] {
                vec.swap(sinker0, sinker0 + 1);
            }
            return;
        }
        _ => (),
    }
    let pivot = median(vec, sinker0, float0);
    let mut sinker = sinker0;
    let mut float = float0;
    loop {
        sink_fully(vec, &mut sinker, pivot);
        float_fully(vec, &mut float, pivot);
        if met(sinker, float) {
            break;
        }
        break_through(vec, &mut sinker, &mut float);
    }
    println!("pivot: {}", pivot);
    println!("{:#?}", &vec[sinker0..=sinker - 1]);
    println!("{:#?}", &vec[float + 1..=float0]);
    release(vec, sinker0, sinker - 1);
    release(vec, float + 1, float0);
}

fn quick_sort(vec: &mut [&str]) {
    release(vec, 0, vec.len() - 1);
}

fn name_score(index: usize, name: &str) -> u32 {
    let position = index as u32 + 1;
    let worth = name.chars().map(|c| c as u32 - 'A' as u32 + 1).sum::<u32>();
    position * worth
}

fn main() {
    let mut names = NAMES.to_vec();
    quick_sort(&mut names);
    let sum: u32 = names
        .iter()
        .enumerate()
        .map(|(i, &n)| name_score(i, n))
        .sum();

    println!("---\n{:#?}", names);
    println!("{}", sum);
    assert_eq!(sum, 26578);
}

const NAMES: &[&str] = &[
    "MARY",
    "PATRICIA",
    "LINDA",
    "BARBARA",
    "ELIZABETH",
    "JENNIFER",
    "MARIA",
    "SUSAN",
    "MARGARET",
    "DOROTHY",
    "LISA",
    "NANCY",
    "KAREN",
    "BETTY",
    "HELEN",
    "SANDRA",
    "DONNA",
    "CAROL",
    "RUTH",
    "SHARON",
    "MICHELLE",
    "LAURA",
    "SARAH",
    "KIMBERLY",
    "DEBORAH",
    "JESSICA",
    "SHIRLEY",
    "CYNTHIA",
];

TODO: switch to the insertion sort when 90 elements have been sorted by the quick sort


2. Merge sort

fn drain_into<'a>(a: &[&'a str], b: &[&'a str], ab: &mut [&'a str]) {
    let (mut x, mut y, mut i) = (0, 0, 0);
    while x < a.len() && y < b.len() {
        if a[x] < b[y] {
            ab[i] = a[x];
            x += 1;
        } else {
            ab[i] = b[y];
            y += 1;
        }
        i += 1;
    }
    if x < a.len() {
        ab[i..].copy_from_slice(&a[x..]);
    }
    if y < b.len() {
        ab[i..].copy_from_slice(&b[y..]);
    }
}

fn merge_sort(segment: &mut [&str]) {
    let n = segment.len();
    let m = n / 2;
    if n <= 1 {
        return;
    }
    merge_sort(&mut segment[0..m]);
    merge_sort(&mut segment[m..n]);
    println!("---\n{:#?}", &segment[0..m]);
    println!("{:#?}", &segment[m..n]);

    let mut tmp: Vec<&str> = segment.to_vec();
    drain_into(&segment[0..m], &segment[m..n], &mut tmp[..]);
    segment.copy_from_slice(&tmp);
    println!("{:#?}", &segment);
}

fn name_score(index: usize, name: &str) -> u32 {
    let position = index as u32 + 1;
    let worth = name.chars().map(|c| c as u32 - 'A' as u32 + 1).sum::<u32>();
    position * worth
}

fn main() {
    let mut names = NAMES.to_vec();
    merge_sort(&mut names);
    let sum: u32 = names
        .iter()
        .enumerate()
        .map(|(i, &n)| name_score(i, n))
        .sum();

    println!("---\n{:#?}", names);
    println!("{}", sum);
    assert_eq!(sum, 26578);
}

const NAMES: &[&str] = &[
    "MARY",
    "PATRICIA",
    "LINDA",
    "BARBARA",
    "ELIZABETH",
    "JENNIFER",
    "MARIA",
    "SUSAN",
    "MARGARET",
    "DOROTHY",
    "LISA",
    "NANCY",
    "KAREN",
    "BETTY",
    "HELEN",
    "SANDRA",
    "DONNA",
    "CAROL",
    "RUTH",
    "SHARON",
    "MICHELLE",
    "LAURA",
    "SARAH",
    "KIMBERLY",
    "DEBORAH",
    "JESSICA",
    "SHIRLEY",
    "CYNTHIA",
];

3. Heap sort

fn heapify(arr: &mut [&str], pi: usize) {
    let lef = 2 * pi + 1;
    let rig = lef + 1;
    if lef >= arr.len() {
        return;
    }
    let max = if rig >= arr.len() {
        lef
    } else if arr[lef] >= arr[rig] {
        lef
    } else {
        rig
    };
    if arr[pi] < arr[max] {
        arr.swap(pi, max);
        println!("---\n     {}", &arr[pi]);
        println!("{}/\\{}", &arr.get(lef).unwrap_or(&"{}"), &arr.get(rig).unwrap_or(&"{}"));
        heapify(arr, max);
    }
}

fn build_heap(arr: &mut [&str]) {
    let parental_indice = 0..arr.len() / 2;
    for pi in parental_indice.rev() {
        heapify(arr, pi);
    }
}

fn serialize(arr: &mut [&str]) {
    for edge in (1..arr.len()).rev() {
        arr.swap(0, edge);
        println!("---\n{:#?}", &arr[edge..]);
        heapify(&mut arr[..edge], 0);
    }
}

fn heap_sort(arr: &mut [&str]) {
    build_heap(arr);
    print_heap(arr);
    serialize(arr);
}

fn name_score(index: usize, name: &str) -> u32 {
    let position = index as u32 + 1;
    let worth = name.chars().map(|c| c as u32 - 'A' as u32 + 1).sum::<u32>();
    position * worth
}

fn main() {
    let mut names = NAMES.to_vec();
    heap_sort(&mut names);
    let sum: u32 = names
        .iter()
        .enumerate()
        .map(|(i, &n)| name_score(i, n))
        .sum();

    println!("---\n{:#?}", names);
    println!("{}", sum);
    assert_eq!(sum, 26578);
}

const NAMES: &[&str] = &[
    "MARY",
    "PATRICIA",
    "LINDA",
    "BARBARA",
    "ELIZABETH",
    "JENNIFER",
    "MARIA",
    "SUSAN",
    "MARGARET",
    "DOROTHY",
    "LISA",
    "NANCY",
    "KAREN",
    "BETTY",
    "HELEN",
    "SANDRA",
    "DONNA",
    "CAROL",
    "RUTH",
    "SHARON",
    "MICHELLE",
    "LAURA",
    "SARAH",
    "KIMBERLY",
    "DEBORAH",
    "JESSICA",
    "SHIRLEY",
    "CYNTHIA",
];

fn print_heap(arr: &[&str]) {
    fn print_white_space(n: usize) {
        for _ in 0..n {
            print!(" ");
        }
    }
    let height = ((arr.len() + 1) as f32).log2() as usize + 1;
    let cell = arr
        .iter()
        .map(|&s| s.len())
        .reduce(|a, b| std::cmp::max(a, b))
        .unwrap();
    let width = cell * 2usize.pow(height as u32);
    let mut levels: Vec<Vec<String>> = vec![vec![]; height + 1];

    for (i, &v) in arr.iter().enumerate() {
        let h = ((i + 1) as f32).log2() as usize + 1;
        let r = levels.get_mut(h).unwrap();
        r.push(format!("{}({})", v, i));
    }
    let last = levels.last_mut().unwrap();
    while last.len() < 2usize.pow(height as u32 - 1) {
        last.push(String::new());
    }
    for r in levels {
        if r.len() == 0 {
            continue;
        }
        let space = (width) / r.len();
        print_white_space(space / 2);
        for (i, c) in r.iter().enumerate() {
            let arrow1 = if i % 2 == 0 { "" } else { "\\" };
            let arrow2 = if i % 2 != 0 { "" } else { "/" };
            print!("{}{}{}", arrow1, c, arrow2);
            print_white_space(space - c.len() - 1);
        }
        println!()
    }
}

4. Bubble sort

fn bubble_sort(vec: &mut Vec<&str>) {
    for i in 0..vec.len() {
        let mut swap_was_required = false;
        for j in 0..vec.len() - i - 1 {
            if vec[j] > vec[j + 1] {
                vec.swap(j, j + 1);
                swap_was_required = true;
            }
        }
        println!("---\n{:#?}", &vec[0..vec.len() - i - 1]);
        println!("{:#?}", &vec[vec.len() - i - 1..vec.len()]);
        if !swap_was_required {
            break;
        }
    }
}

fn name_score(index: usize, name: &str) -> u32 {
    let position = index as u32 + 1;
    let worth = name.chars().map(|c| c as u32 - 'A' as u32 + 1).sum::<u32>();
    position * worth
}

fn main() {
    let mut names = NAMES.to_vec();
    bubble_sort(&mut names);
    let sum: u32 = names
        .iter()
        .enumerate()
        .map(|(i, &n)| name_score(i, n))
        .sum();

    println!("---\n{:#?}", names);
    println!("{}", sum);
    assert_eq!(sum, 26578);
}

const NAMES: &[&str] = &[
    "MARY",
    "PATRICIA",
    "LINDA",
    "BARBARA",
    "ELIZABETH",
    "JENNIFER",
    "MARIA",
    "SUSAN",
    "MARGARET",
    "DOROTHY",
    "LISA",
    "NANCY",
    "KAREN",
    "BETTY",
    "HELEN",
    "SANDRA",
    "DONNA",
    "CAROL",
    "RUTH",
    "SHARON",
    "MICHELLE",
    "LAURA",
    "SARAH",
    "KIMBERLY",
    "DEBORAH",
    "JESSICA",
    "SHIRLEY",
    "CYNTHIA",
];

5. Selection sort

fn selection_sort(vec: &mut Vec<&str>) {
    for i in 0..vec.len() {
        let mut min_index = i;
        for j in (i + 1)..vec.len() {
            if vec[j] < vec[min_index] {
                min_index = j;
            }
        }
        vec.swap(i, min_index);
        println!("---\n{:#?}", &vec[0..=i]);
        println!("{:#?}", &vec[std::cmp::min(i + 1, vec.len())..vec.len()]);
    }
}

fn name_score(index: usize, name: &str) -> u32 {
    let position = index as u32 + 1;
    let worth = name.chars().map(|c| c as u32 - 'A' as u32 + 1).sum::<u32>();
    position * worth
}

fn main() {
    let mut names = NAMES.to_vec();
    selection_sort(&mut names);
    let sum: u32 = names
        .iter()
        .enumerate()
        .map(|(i, &n)| name_score(i, n))
        .sum();

    println!("---\n{:#?}", names);
    println!("{}", sum);
    assert_eq!(sum, 26578);
}

const NAMES: &[&str] = &[
    "MARY",
    "PATRICIA",
    "LINDA",
    "BARBARA",
    "ELIZABETH",
    "JENNIFER",
    "MARIA",
    "SUSAN",
    "MARGARET",
    "DOROTHY",
    "LISA",
    "NANCY",
    "KAREN",
    "BETTY",
    "HELEN",
    "SANDRA",
    "DONNA",
    "CAROL",
    "RUTH",
    "SHARON",
    "MICHELLE",
    "LAURA",
    "SARAH",
    "KIMBERLY",
    "DEBORAH",
    "JESSICA",
    "SHIRLEY",
    "CYNTHIA",
];

6. Insertion sort

fn insertion_sort(vec: &mut [&str]) {
    for i in 0..vec.len() {
        for j in (0..i).rev() {
            if vec[j] < vec[j + 1] {
                break;
            }
            vec.swap(j, j + 1);
        }
        println!("---\n{:#?}", &vec[0..=i]);
        println!("{:#?}", &vec[i + 1..vec.len()]);
    }
}

fn name_score(index: usize, name: &str) -> u32 {
    let position = index as u32 + 1;
    let worth = name.chars().map(|c| c as u32 - 'A' as u32 + 1).sum::<u32>();
    position * worth
}

fn main() {
    let mut names = NAMES.to_vec();
    insertion_sort(&mut names);
    let sum: u32 = names
        .iter()
        .enumerate()
        .map(|(i, &n)| name_score(i, n))
        .sum();

    println!("---\n{:#?}", names);
    println!("{}", sum);
    assert_eq!(sum, 26578);
}

const NAMES: &[&str] = &[
    "MARY",
    "PATRICIA",
    "LINDA",
    "BARBARA",
    "ELIZABETH",
    "JENNIFER",
    "MARIA",
    "SUSAN",
    "MARGARET",
    "DOROTHY",
    "LISA",
    "NANCY",
    "KAREN",
    "BETTY",
    "HELEN",
    "SANDRA",
    "DONNA",
    "CAROL",
    "RUTH",
    "SHARON",
    "MICHELLE",
    "LAURA",
    "SARAH",
    "KIMBERLY",
    "DEBORAH",
    "JESSICA",
    "SHIRLEY",
    "CYNTHIA",
];
Problem 23 "Non-abundant sums"

A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.

A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.

As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.

Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.

問 23 「非過剰数和」

完全数とは, その数の真の約数の和がそれ自身と一致する数のことである. たとえば, 28の真の約数の和は, 1 + 2 + 4 + 7 + 14 = 28 であるので, 28は完全数である.

真の約数の和がその数よりも少ないものを不足数といい, 真の約数の和がその数よりも大きいものを過剰数と呼ぶ.

12は, 1 + 2 + 3 + 4 + 6 = 16 となるので, 最小の過剰数である. よって2つの過剰数の和で書ける最少の数は24である. 数学的な解析により, 28123より大きい任意の整数は2つの過剰数の和で書けることが知られている. 2つの過剰数の和で表せない最大の数がこの上限よりも小さいことは分かっているのだが, この上限を減らすことが出来ていない.

2つの過剰数の和で書き表せない正の整数の総和を求めよ.

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

fn rule_out(sieve: &mut Vec<bool>, prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn primes(below: u32) -> Vec<u32> {
    let mut primes: Vec<u32> = vec![2u32, 3u32];
    let mut sieve = vec![true; below as usize];
    let sqrt = (sieve.len() as f32).sqrt() as usize;
    let mut index = Index::new();
    while index.i <= sqrt {
        if sieve[index.i] {
            primes.push(index.i as u32);
            rule_out(&mut sieve, index.i);
        }
        index.increment();
    }
    while index.i < sieve.len() {
        if sieve[index.i] {
            primes.push(index.i as u32);
        }
        index.increment();
    }
    primes
}

struct AbundantNumberScanner {
    below: u32,
    _primes: Vec<u32>,
    _pair_sieve: Vec<bool>,
}

impl AbundantNumberScanner {
    fn new(below: u32) -> Self {
        Self {
            below: below,
            _primes: primes(below),
            _pair_sieve: vec![false; below as usize],
        }
    }
    fn _divide_fully(&self, n: &mut u32, d: u32, side: &mut u32, sum: &mut u32) {
        if *n % d != 0 {
            return;
        }
        let mut exp = 0u32;
        while {
            *n /= d;
            exp += 1;
            *n % d == 0
        } {}
        *side = (*n as f32).sqrt() as u32;
        *sum *= (d.pow(exp + 1) - 1) / (d - 1);
    }
    fn _sum_of_divisors(&mut self, mut n: u32) -> u32 {
        let mut side = (n as f32).sqrt() as u32;
        let mut sum = 1u32;
        for &p in self._primes.iter() {
            if p > side || n == 1 {
                break;
            }
            self._divide_fully(&mut n, p, &mut side, &mut sum);
        }
        if n != 1 {
            sum *= (n * n - 1) / (n - 1);
        }
        sum
    }
    fn init_abundant_num_pair_sieve(&mut self) {
        let mut abundant_numbers = vec![];
        for n in 12..self.below {
            let sum = self._sum_of_divisors(n) - n;
            if sum > n {
                abundant_numbers.push(n);
            }
        }
        for (i, &a) in abundant_numbers.iter().enumerate() {
            for &b in abundant_numbers[i..].iter() {
                if let Some(n) = self._pair_sieve.get_mut((a + b) as usize) {
                    *n = true;
                }
            }
        }
    }
    fn non_pair_sum(&mut self) -> u32 {
        let mut non_pair_sum = 0u32;
        for n in 1..self.below {
            if !self._pair_sieve[n as usize] {
                non_pair_sum += n;
            }
        }
        non_pair_sum
    }
}

fn main() {
    let mut a = AbundantNumberScanner::new(28_124);
    a.init_abundant_num_pair_sieve();
    let sum = a.non_pair_sum();

    println!("{}", sum);
    assert_eq!(sum, 4179871);
}
Problem 24 "Lexicographic permutations"

A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4. If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:

012 021 102 120 201 210

What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?

問 24 「辞書式順列」

順列とはモノの順番付きの並びのことである. たとえば, 3124は数 1, 2, 3, 4 の一つの順列である. すべての順列を数の大小でまたは辞書式に並べたものを辞書順と呼ぶ. 0と1と2の順列を辞書順に並べると

012 021 102 120 201 210

になる.

0,1,2,3,4,5,6,7,8,9からなる順列を辞書式に並べたときの100万番目はいくつか?

fn factorial(n: u64) -> u64 {
    match n {
        0 | 1 => 1,
        _ => factorial(n - 1) * n,
    }
}

fn main() {
    let mut reminder = 1_000_000u64 - 1;
    let mut items_with_order = vec![0u64, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut millionth_element = 0u64;
    for weight in (0..items_with_order.len()).rev() {
        let unit = factorial(weight as u64);
        let quot = reminder / unit;
        reminder -= quot * unit;
        millionth_element *= 10;
        millionth_element += items_with_order.remove(quot as usize);
    }

    println!("{}", millionth_element);
    assert_eq!(millionth_element, 2783915460);
}
Problem 25 "1000-digit Fibonacci number"

The Fibonacci sequence is defined by the recurrence relation:

Fn = Fn−1 + Fn−2, where F1 = 1 and F2 = 1.

Hence the first 12 terms will be:

F1 = 1
F2 = 1
F3 = 2
F4 = 3
F5 = 5
F6 = 8
F7 = 13
F8 = 21
F9 = 34
F10 = 55
F11 = 89
F12 = 144

The 12th term, F12, is the first term to contain three digits.

What is the index of the first term in the Fibonacci sequence to contain 1000 digits?

問 25 「1000桁のフィボナッチ数」

フィボナッチ数列は以下の漸化式で定義される:

最初の12項は以下である.

12番目の項, F12が3桁になる最初の項である.

1000桁になる最初の項の番号を答えよ.

fn main() {
    let constant_1 = (1f64 + 5f64.sqrt()).log10() - 2f64.log10();
    let constant_2 = 5f64.log10() / 2f64;
    let digits_of_nth_fibonacci = |nth: f64| -> f64 { nth * constant_1 - constant_2 };

    let ratio = (1f64 + 5f64.sqrt()) / 2f64;
    let iteration = 10f64.log(ratio);
    let estimation = iteration * 999f64;
    println!("estimation: {} th Fibonacci number would have 1000 digits", estimation);
    let mut n = (estimation - iteration).floor(); // rollback to 999 digits
    assert!(digits_of_nth_fibonacci(n) < 999f64);
    while digits_of_nth_fibonacci(n) < 999f64 {
        n += 1f64;
    }

    println!("{}", n);
    assert_eq!(n as u32, 4782);
}
Problem 26 "Reciprocal cycles"

A unit fraction contains 1 in the numerator. The decimal representation of the unit fractions with denominators 2 to 10 are given:

1/2= 0.5
1/3= 0.(3)
1/4= 0.25
1/5= 0.2
1/6= 0.1(6)
1/7= 0.(142857)
1/8= 0.125
1/9= 0.(1)
1/10= 0.1

Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle. It can be seen that 1/7 has a 6-digit recurring cycle.

Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part.

問 26 「逆数の循環節 その1」

単位分数とは分子が1の分数である. 分母が2から10の単位分数を10進数で表記すると次のようになる.

0.1(6)は 0.166666... という数字であり, 1桁の循環節を持つ. 1/7 の循環節は6桁ある.

d < 1000 の条件で、 1/d の中で小数部の循環節が最も長くなるような d を求めよ.

1. Long division

struct UnitFraction {
    reciprocal: u32,
    repetend_length: u32,
}

fn is_recurring(mut n: u32) -> bool {
    if n % 2 != 0 && n % 5 != 0 {
        return true;
    }
    for &d in [2u32, 5].iter() {
        while n % d == 0 {
            n /= d;
        }
        if n == 1 {
            return false;
        }
    }
    true
}

fn repetend_length(n: u32, residue_history: &mut [u32]) -> u32 {
    assert!(residue_history.len() >= n as usize);
    let mut dividend = 1u32;
    for nth_time_around in 0u32.. {
        let residue = dividend % n;
        let last_time = residue_history[residue as usize];
        if last_time != 0 {
            return nth_time_around - last_time;
        }
        residue_history[residue as usize] = nth_time_around;
        dividend = residue * 10;
    }
    panic!("irrational number")
}

fn number_with_longest_recurring_cycle(below: u32) -> u32 {
    assert!(below > 3);
    let mut uf = UnitFraction {
        reciprocal: 1,
        repetend_length: 0,
    };
    let blank = vec![0u32; below as usize];
    let mut residue_history = vec![0u32; below as usize];
    for n in (1u32..below).rev() {
        if !is_recurring(n) {
            continue;
        }
        residue_history[..n as usize].copy_from_slice(&blank[..n as usize]);
        let length = repetend_length(n, &mut residue_history[0..n as usize]);
        if n - 1 == length {
            return n;
        }
        if length > uf.repetend_length {
            uf.repetend_length = length;
            uf.reciprocal = n;
        }
    }
    uf.reciprocal
}

fn main() {
    let num = number_with_longest_recurring_cycle(1000);
    println!("{}", num);
    assert_eq!(num, 983);

    assert_eq!(number_with_longest_recurring_cycle(10000), 9967);
    assert_eq!(number_with_longest_recurring_cycle(9968), 9967);
    assert_eq!(number_with_longest_recurring_cycle(5000), 4967);
    assert_eq!(number_with_longest_recurring_cycle(8), 7);
    assert_eq!(number_with_longest_recurring_cycle(20), 19);
    assert_eq!(number_with_longest_recurring_cycle(18), 17);
    assert_eq!(number_with_longest_recurring_cycle(25), 23);
    assert_eq!(number_with_longest_recurring_cycle(6), 3);
}

2. Prime numbers

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

fn rule_out(sieve: &mut Vec<bool>, prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn primes(below: u32) -> Vec<u32> {
    let mut primes: Vec<u32> = vec![2u32, 3u32];
    let mut sieve = vec![true; below as usize];
    let sqrt = (sieve.len() as f32).sqrt() as usize;
    let mut index = Index::new();
    while index.i <= sqrt {
        if sieve[index.i] {
            primes.push(index.i as u32);
            rule_out(&mut sieve, index.i);
        }
        index.increment();
    }
    while index.i < sieve.len() {
        if sieve[index.i] {
            primes.push(index.i as u32);
        }
        index.increment();
    }
    primes
}

fn repetend_length(n: u32) -> u32 {
    assert!(n % 2 != 0 && n % 5 != 0);
    let mut dividend = 10u32;
    for nth_time_around in 1u32.. {
        let residue = dividend % n;
        if residue == 1 {
            return nth_time_around
        }
        dividend = residue * 10;
    }
    panic!("irrational number")
}

fn number_with_longest_recurring_cycle(below: u32) -> u32 {
    if below < 7 {
        return 3;
    }
    let primes = primes(below);
    for &p in primes.iter().rev() {
        if repetend_length(p) == p - 1 {
            return p;
        }
    }
    panic!("couldn't find a point that n - 1 == repetend_length(n)")
}

fn main() {
    let num = number_with_longest_recurring_cycle(1000);
    println!("{}", num);
    assert_eq!(num, 983);

    assert_eq!(number_with_longest_recurring_cycle(10000), 9967);
    assert_eq!(number_with_longest_recurring_cycle(9968), 9967);
    assert_eq!(number_with_longest_recurring_cycle(5000), 4967);
    assert_eq!(number_with_longest_recurring_cycle(8), 7);
    assert_eq!(number_with_longest_recurring_cycle(20), 19);
    assert_eq!(number_with_longest_recurring_cycle(18), 17);
    assert_eq!(number_with_longest_recurring_cycle(25), 23);
    assert_eq!(number_with_longest_recurring_cycle(6), 3);
}

3. Divisors of p-1 and modular exponentiation

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

fn rule_out(sieve: &mut Vec<bool>, prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn primes(below: u32) -> Vec<u32> {
    let mut primes: Vec<u32> = vec![2u32, 3u32];
    let mut sieve = vec![true; below as usize];
    let sqrt = (sieve.len() as f32).sqrt() as usize;
    let mut index = Index::new();
    while index.i <= sqrt {
        if sieve[index.i] {
            primes.push(index.i as u32);
            rule_out(&mut sieve, index.i);
        }
        index.increment();
    }
    while index.i < sieve.len() {
        if sieve[index.i] {
            primes.push(index.i as u32);
        }
        index.increment();
    }
    primes
}

fn mod_pow(mut a: u32, mut exp: u32, m: u32) -> u32 {
    if m == 1 {
        return 0;
    }
    if exp == 0 {
        return 1;
    }
    let mut result = 1;
    a %= m;
    loop {
        if exp % 2 == 1 {
            result *= a;
            result %= m;
        }
        exp >>= 1;
        if exp == 0 {
            break;
        }
        a *= a;
        a %= m;
    }
    result
}

fn list_divisors(n: u32) -> Vec<u32> {
    let side = (n as f32).sqrt() as u32;
    let mut vec = vec![];
    for d in 1..=side {
        if n % d == 0 {
            vec.push(d);
            if d != side {
                vec.push(n / d);
            }
        }
    }
    vec.sort();
    vec
}

fn number_with_longest_recurring_cycle(below: u32) -> u32 {
    if below < 7 {
        return 3;
    }
    let primes = primes(below);
    'next_prime: for &p in primes.iter().rev() {
        let divisors = list_divisors(p - 1);
        for &d in &divisors[0..divisors.len() - 1] {
            if mod_pow(10, d, p) == 1 {
                continue 'next_prime;
            }
        }
        return p;
    }
    panic!("couldn't find a point that n - 1 == recurring_length(n)")
}

fn main() {
    let num = number_with_longest_recurring_cycle(1000);
    println!("{}", num);
    assert_eq!(num, 983);

    assert_eq!(number_with_longest_recurring_cycle(10000), 9967);
    assert_eq!(number_with_longest_recurring_cycle(9968), 9967);
    assert_eq!(number_with_longest_recurring_cycle(5000), 4967);
    assert_eq!(number_with_longest_recurring_cycle(8), 7);
    assert_eq!(number_with_longest_recurring_cycle(20), 19);
    assert_eq!(number_with_longest_recurring_cycle(18), 17);
    assert_eq!(number_with_longest_recurring_cycle(25), 23);
    assert_eq!(number_with_longest_recurring_cycle(6), 3);
}

Reference

Problem 27 "Quadratic primes"

Euler discovered the remarkable quadratic formula:

\[ n^2 + n + 41 \]

It turns out that the formula will produce 40 primes for the consecutive integer values \( 0 \le n \le 39 \). However, when \( n = 40, 40^2 + 40 + 41 = 40(40 + 1) + 41 \) is divisible by 41, and certainly when \(n = 41, 41^2 + 41 + 41\) is clearly divisible by 41.

The incredible formula \( n^2 - 79n + 1601 \) was discovered, which produces 80 primes for the consecutive values \( 0 \le n \le 79\). The product of the coefficients, −79 and 1601, is −126479.

Considering quadratics of the form:

\( n^2 + an + b \), where \( |a| < 1000 \) and \( |b| \le 1000 \)

where \( |n| \) is the modulus/absolute value of \( n \)
e.g. \( |11| = 11 \) and \( |-4| = 4 \)

Find the product of the coefficients, \( a \) and \( b \), for the quadratic expression that produces the maximum number of primes for consecutive values of \( n \), starting with \( n = 0 \).

問 27 「二次式素数」

オイラーは以下の二次式を考案している:

\[ n^2 + n + 41 \]

この式は, n を0から39までの連続する整数としたときに40個の素数を生成する. しかし, n = 40 のとき \( 40^2 + 40 + 41 = 40(40 + 1) + 41 \) となり41で割り切れる. また, n = 41 のときは \( 41^2 + 41 + 41 \) であり明らかに41で割り切れる.

計算機を用いて, 二次式 \( n^2 - 79n + 1601 \) という式が発見できた. これは n = 0 から 79 の連続する整数で80個の素数を生成する. 係数の積は, -79 × 1601 で -126479である.

さて, |a| < 1000, |b| ≤ 1000 として以下の二次式を考える (ここで |a| は絶対値): 例えば |11| = 11 |-4| = 4である.

\[ n^2 + an + b \]

n = 0 から始めて連続する整数で素数を生成したときに最長の長さとなる上の二次式の, 係数 a, b の積を答えよ.

struct Sieve {
    _sieve: Vec<bool>,
}

impl Sieve {
    fn rule_out(&mut self, prime: usize) {
        for i in (prime * prime..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn init(&mut self) {
        let sqrt = (self._sieve.len() as f64).sqrt() as usize;
        let mut index = 5usize;
        for &i in [2usize, 4].iter().cycle() {
            if index > sqrt {
                break;
            }
            if self._sieve[index] {
                self.rule_out(index);
            }
            index += i;
        }
    }
    fn new(below: u32) -> Self {
        assert!(below > 4);
        let sieve = vec![true; below as usize];
        let mut s = Self { _sieve: sieve };
        s.init();
        s
    }
    fn is_prime(&self, n: u32) -> bool {
        assert!(n < self._sieve.len() as u32);
        if n == 2 || n == 3 {
            return true;
        }
        if n == 0 || n == 1 || n % 2 == 0 || n % 3 == 0 {
            return false;
        }
        self._sieve[n as usize]
    }
    fn primes(&self, below: u32) -> Vec<u32> {
        let mut primes: Vec<u32> = vec![2u32, 3u32];
        let mut index = 5usize;
        for &i in [2usize, 4].iter().cycle() {
            if index >= below as usize {
                break;
            }
            if self._sieve[index] {
                primes.push(index as u32);
            }
            index += i;
        }
        primes
    }
}

fn quadratic_formula(n: u32, a: i32, b: u32) -> i32 {
    (n * n) as i32 + a * n as i32 + b as i32
}

fn main() {
    let (mut nmax, mut amax, mut bmax) = (1u32, 0i32, 0u32);
    let sieve = Sieve::new(2_000_000);
    for b in sieve.primes(1001) {
        for a in (-(b as i32) + 1)..=999 {
            let mut n = 1;
            let mut v = quadratic_formula(1, a, b);
            if !(v > 1 && sieve.is_prime(v as u32)) {
                continue;
            }
            while {
                n += 1;
                v = quadratic_formula(n, a, b);
                v > 1 && sieve.is_prime(v as u32)
            } {}
            if n > nmax {
                nmax = n;
                amax = a;
                bmax = b;
            }
        }
    }
    let product = amax * bmax as i32;

    println!("{}", product);
    assert_eq!(product, -59231);
}
Problem 28 "Number spiral diagonals"

Starting with the number 1 and moving to the right in a clockwise direction a 5 by 5 spiral is formed as follows:

21 22 23 24 25
20  7  8  9 10
19  6  1  2 11
18  5  4  3 12
17 16 15 14 13

It can be verified that the sum of the numbers on the diagonals is 101.

What is the sum of the numbers on the diagonals in a 1001 by 1001 spiral formed in the same way?

問 28 「螺旋状に並んだ数の対角線」

1から初めて右方向に進み時計回りに数字を増やしていき, 5×5の螺旋が以下のように生成される:

両対角線上の数字の合計は101であることが確かめられる.

1001×1001の螺旋を同じ方法で生成したとき, 対角線上の数字の和はいくつか?

fn main() {
    let width = 1001u64;
    assert!(width % 2 == 1);
    let n = width / 2;
    let sum = 16 * n * (n + 1) * (2 * n + 1) / 6 + 4 * n * (1 + n) / 2 + 4 * n + 1;
    println!("{}", sum);
    assert_eq!(sum, 669171001);
}
Problem 29 "Distinct powers"

Consider all integer combinations of ab for 2 ≤ a ≤ 5 and 2 ≤ b ≤ 5:

22=4, 23=8, 24=16, 25=32
32=9, 33=27, 34=81, 35=243
42=16, 43=64, 44=256, 45=1024
52=25, 53=125, 54=625, 55=3125

If they are then placed in numerical order, with any repeats removed, we get the following sequence of 15 distinct terms:

4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125

How many distinct terms are in the sequence generated by ab for 2 ≤ a ≤ 100 and 2 ≤ b ≤ 100?

問 29 「個別のべき乗」

2 ≤ a ≤ 5 と 2 ≤ b ≤ 5について, \( 2^5 \) を全て考えてみよう:

これらを小さい順に並べ, 同じ数を除いたとすると, 15個の項を得る:

4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125

2 ≤ a ≤ 100, 2 ≤ b ≤ 100 で同じことをしたときいくつの異なる項が存在するか?

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

fn rule_out(sieve: &mut Vec<bool>, prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn primes(below: u32) -> Vec<u32> {
    let mut primes: Vec<u32> = vec![2u32, 3u32];
    let mut sieve = vec![true; below as usize];
    let sqrt = (sieve.len() as f32).sqrt() as usize;
    let mut index = Index::new();
    while index.i <= sqrt {
        if sieve[index.i] {
            primes.push(index.i as u32);
            rule_out(&mut sieve, index.i);
        }
        index.increment();
    }
    while index.i < sieve.len() {
        if sieve[index.i] {
            primes.push(index.i as u32);
        }
        index.increment();
    }
    primes
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
struct Factor {
    prime: u32,
    exp: u32,
}

fn divide_fully(n: &mut u32, d: u32, side: &mut u32, factors: &mut Vec<Factor>) {
    if *n % d != 0 {
        return;
    }
    let mut exp = 0u32;
    while {
        *n /= d;
        exp += 1;
        *n % d == 0
    } {}
    factors.push(Factor { prime: d, exp: exp });
    *side = (*n as f32).sqrt() as u32;
}

fn factorize(mut n: u32, primes: &[u32]) -> Vec<Factor> {
    let mut factors = vec![];
    let mut side = (n as f32).sqrt() as u32;
    for &p in primes.iter() {
        if p > side || n == 1 {
            break;
        }
        divide_fully(&mut n, p, &mut side, &mut factors);
    }
    if n != 1 {
        factors.push(Factor { prime: n, exp: 1 });
    }
    factors
}

fn count_duplication(arr: &mut [Vec<Factor>]) -> u32 {
    arr.sort();
    let mut dup = 0u32;
    for i in 1..arr.len() {
        if arr[i - 1] == arr[i] {
            dup += 1;
        }
    }
    dup
}

fn main() {
    let primes = primes(101);
    let mut expressions = Vec::new();
    (2..=100u32).map(|a| factorize(a, &primes)).for_each(|a| {
        for b in 2..=100u32 {
            let mut ab = a.to_vec();
            ab.iter_mut().for_each(|f| f.exp *= b);
            expressions.push(ab);
        }
    });
    let c = expressions.len() as u32 - count_duplication(&mut expressions);

    println!("{}", c);
    assert_eq!(c, 9183);
}
Problem 30 "Digit fifth powers"

Surprisingly there are only three numbers that can be written as the sum of fourth powers of their digits:

1634 = 14 + 64 + 34 + 44
8208 = 84 + 24 + 04 + 84
9474 = 94 + 44 + 74 + 44

As 1 = 14 is not a sum it is not included.

The sum of these numbers is 1634 + 8208 + 9474 = 19316.

Find the sum of all the numbers that can be written as the sum of fifth powers of their digits.

問 30 「各桁の5乗」

驚くべきことに, 各桁を4乗した数の和が元の数と一致する数は3つしかない.

ただし, \( 1=1^4 \) は含まないものとする.

この数たちの和は 1634 + 8208 + 9474 = 19316 である.

各桁を5乗した数の和が元の数と一致するような数の総和を求めよ.

fn match_pow_sum(target: u32, pow_sum_999_fold: &[u32; 999]) -> bool {
    let mut digits = target;
    let mut sum = 0;
    while digits > 0 {
        let d = digits % 1000;
        digits /= 1000;
        if d == 0 {
            continue;
        }
        sum += pow_sum_999_fold[d as usize - 1];
        if sum > target {
            return false;
        }
    }
    sum == target
}

fn pow_sum_999_fold(power_ninefold: &[u32; 9]) -> [u32; 999] {
    let mut pow_sum_999_fold = [0u32; 999];
    for i in 1..=pow_sum_999_fold.len() {
        let mut sum = 0;
        let mut digits = i as u32;
        while digits > 0 {
            let d = digits % 10;
            digits /= 10;
            if d != 0 {
                sum += power_ninefold[d as usize - 1];
            }
        }
        pow_sum_999_fold[i - 1] = sum;
    }
    pow_sum_999_fold
}

fn digit_range_max(powed_nine: u32) -> u32 {
    let mut digit_min = 1u32;
    let mut pow_sum_max = powed_nine;
    while digit_min < pow_sum_max {
        digit_min *= 10;
        pow_sum_max += powed_nine;
    }
    pow_sum_max - powed_nine
}

fn main() {
    let e = 5;
    let mut power_ninefold = [0u32; 9];
    (1..=9u32).for_each(|n| power_ninefold[n as usize - 1] = n.pow(e));
    let pow_sum_999_fold = pow_sum_999_fold(&power_ninefold);
    let digits_max = digit_range_max(power_ninefold[8]);
    let sum = (2..=digits_max)
        .filter(|&d| match_pow_sum(d, &pow_sum_999_fold))
        .sum::<u32>();

    println!("{}", sum);
    assert_eq!(sum, 443839);
}
Problem 31 "Coin sums"

In the United Kingdom the currency is made up of pound (£) and pence (p). There are eight coins in general circulation:

1p, 2p, 5p, 10p, 20p, 50p, £1 (100p), and £2 (200p).

It is possible to make £2 in the following way:

1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p

How many different ways can £2 be made using any number of coins?

問 31 「硬貨の和」

イギリスでは硬貨はポンド£とペンスpがあり,一般的に流通している硬貨は以下の8種類である.

1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p).

以下の方法で£2を作ることが可能である.

1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p

これらの硬貨を使って£2を作る方法は何通りあるか?

use std::cmp::Ordering;

fn coin_change_combination(payment: usize, coins: &[usize]) -> u32 {
    assert!(payment > 0 && coins.len() > 0);
    let mut table = vec![vec![0u32; payment]; coins.len()];
    for c in 0..table.len() {
        for p in 0..table[c].len() {
            let v_no = if c == 0 { 0u32 } else { table[c - 1][p] };
            let v_we = match (p + 1).partial_cmp(&(coins[c])).expect("NaNs") {
                Ordering::Less => 0u32,
                Ordering::Equal => 1u32,
                Ordering::Greater => table[c][p - coins[c]],
            };
            table[c][p] = v_no + v_we;
        }
    }
    table[coins.len() - 1][payment - 1]
}

fn main() {
    let payment = 200usize;
    let coins = [1usize, 2, 5, 10, 20, 50, 100, 200];
    let comb = coin_change_combination(payment, &coins);

    println!("{}", comb);
    assert_eq!(comb, 73682);
    assert_eq!(coin_change_combination(8, &[1, 3, 5, 7]), 6);
    assert_eq!(coin_change_combination(3, &[1, 2]), 2);
    assert_eq!(coin_change_combination(2, &[1, 2]), 2);
    assert_eq!(coin_change_combination(1, &[1, 2]), 1);
    assert_eq!(coin_change_combination(5, &[2, 3]), 1);
    assert_eq!(coin_change_combination(5, &[1, 2, 3]), 5);
    assert_eq!(coin_change_combination(5, &[1]), 1);
    assert_eq!(coin_change_combination(2, &[3]), 0);
}
Problem 32 "Pandigital products"

We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly once; for example, the 5-digit number, 15234, is 1 through 5 pandigital.

The product 7254 is unusual, as the identity, 39 × 186 = 7254, containing multiplicand, multiplier, and product is 1 through 9 pandigital.

Find the sum of all products whose multiplicand/multiplier/product identity can be written as a 1 through 9 pandigital.

HINT: Some products can be obtained in more than one way so be sure to only include it once in your sum.

問 32 「パンデジタル積」

すべての桁に 1 から n が一度だけ使われている数を n桁の数がパンデジタル (pandigital) であるということにしよう: 例えば5桁の数 15234 は1から5のパンデジタルである.

7254 は面白い性質を持っている. 39 × 186 = 7254 と書け, 掛けられる数, 掛ける数, 積が1から9のパンデジタルとなる.

掛けられる数/掛ける数/積が1から9のパンデジタルとなるような積の総和を求めよ.

HINT: いくつかの積は, 1通り以上の掛けられる数/掛ける数/積の組み合わせを持つが1回だけ数え上げよ.

use std::ops::RangeInclusive;

fn is_pandigital(a: u32, b: u32, ab: u32) -> bool {
    let mut bits = 0u16;
    for n in [a, b, ab].iter_mut() {
        while *n > 0 {
            let d = *n % 10;
            bits |= 1 << d;
            *n /= 10;
        }
    }
    bits == 0b1111111110u16
}

fn sum_distinct(arr: &mut [u32]) -> u32 {
    arr.sort();
    let mut sum = 0u32;
    if let Some(&n) = arr.get(0) {
        sum += n;
    }
    for i in 1..arr.len() {
        if arr[i - 1] != arr[i] {
            sum += arr[i];
        }
    }
    sum
}

fn explore_pandigital_combinations(
    a: RangeInclusive<u32>,
    b: RangeInclusive<u32>,
    products: &mut Vec<u32>,
) {
    for a in a {
        for b in b.clone() {
            let ab = a * b;
            if ab > 9876 {
                break;
            }
            if is_pandigital(a, b, ab) {
                products.push(ab);
            }
        }
    }
}

fn main() {
    let mut products = Vec::<u32>::new();
    explore_pandigital_combinations(2..=9, 1234..=9876, &mut products);
    explore_pandigital_combinations(12..=98, 123..=987, &mut products);
    let sum = sum_distinct(&mut products);

    println!("{}", sum);
    assert_eq!(sum, 45228);
}
Problem 33 "Digit cancelling fractions"

The fraction 49/98 is a curious fraction, as an inexperienced mathematician in attempting to simplify it may incorrectly believe that 49/98 = 4/8, which is correct, is obtained by cancelling the 9s.

We shall consider fractions like, 30/50 = 3/5, to be trivial examples.

There are exactly four non-trivial examples of this type of fraction, less than one in value, and containing two digits in the numerator and denominator.

If the product of these four fractions is given in its lowest common terms, find the value of the denominator.

問 33 「桁消去分数」

49/98は面白い分数である.「分子と分母からそれぞれ9を取り除くと, 49/98 = 4/8 となり, 簡単な形にすることができる」と経験の浅い数学者が誤って思い込んでしまうかもしれないからである. (方法は正しくないが,49/98 = 4/8の場合にはたまたま正しい約分になってしまう.)

我々は30/50 = 3/5 のようなタイプは自明な例だとする.

このような分数のうち, 1より小さく分子・分母がともに2桁の数になるような「自明でない」ものは, 4個ある.

その4個の分数の積が約分された形で与えられたとき, 分母の値を答えよ.

fn gcd(mut a: u32, mut b: u32) -> u32 {
    assert!(a != 0 && b != 0);
    while b != 0 {
        let r = a % b;
        a = b;
        b = r;
    }
    a
}

fn main() {
    let mut numerator = 1u32;
    let mut denominator = 1u32;
    for a in 1u32..=9 {
        for c in a..=9 {
            for d in a..c {
                if (10 * a + c) * d == (10 * c + d) * a && a != d {
                    numerator *= a;
                    denominator *= d;
                }
            }
        }
    }
    let gcd = gcd(numerator, denominator);
    let ans = denominator / gcd;

    println!("{}", ans);
    assert_eq!(ans, 100);
}
Problem 34 "Digit factorials"

145 is a curious number, as 1! + 4! + 5! = 1 + 24 + 120 = 145.

Find the sum of all numbers which are equal to the sum of the factorial of their digits.

Note: As 1! = 1 and 2! = 2 are not sums they are not included.

問 34 「桁の階乗」

145は面白い数である. 1! + 4! + 5! = 1 + 24 + 120 = 145となる.

各桁の数の階乗の和が自分自身と一致するような数の和を求めよ.

''注:'' 1! = 1 と 2! = 2 は総和に含めてはならない.

fn build_factorial_tenfold() -> [u32; 10] {
    let mut acc = 1u32;
    let mut factorial_tenfold = [1u32; 10];
    for n in 1..=9 {
        acc *= n;
        factorial_tenfold[n as usize] = acc;
    }
    factorial_tenfold
}

fn factorial_sum_10000_fold(factorial_tenfold: &[u32; 10]) -> [u32; 10000] {
    let mut factorial_sum_10000_fold = [0u32; 10000];
    factorial_sum_10000_fold[0] = 1;
    for i in 1..factorial_sum_10000_fold.len() {
        let mut sum = 0;
        let mut digits = i as u32;
        while digits > 0 {
            let d = digits % 10;
            digits /= 10;
            sum += factorial_tenfold[d as usize];
        }
        factorial_sum_10000_fold[i] = sum;
    }
    factorial_sum_10000_fold
}

fn zero_pad_10000(carry: u32, residue: u32, sum: &mut u32) {
    match (carry > 0, residue) {
        (false, _) => (),
        (true, 0..=9) => *sum += 3,
        (true, 10..=99) => *sum += 2,
        (true, 100..=999) => *sum += 1,
        _ => (),
    }
}

fn match_factorial_sum_10000(target: u32, factorial_sum_10000_fold: &[u32; 10000]) -> bool {
    let mut digits = target;
    let mut sum = 0;
    while digits > 0 {
        let d = digits % 10000;
        digits /= 10000;
        sum += factorial_sum_10000_fold[d as usize];
        zero_pad_10000(digits, d, &mut sum);
        if sum > target {
            return false;
        }
    }
    sum == target
}

fn digit_range_max(fact_nine: u32) -> u32 {
    let mut digit_min = 1u32;
    let mut fact_sum_max = fact_nine;
    while digit_min < fact_nine {
        digit_min *= 10;
        fact_sum_max += fact_nine;
    }
    fact_sum_max - fact_nine
}

fn main() {
    let factorial_tenfold = build_factorial_tenfold();
    let factorial_sum_10000_fold = factorial_sum_10000_fold(&factorial_tenfold);
    let digit_range_max = digit_range_max(factorial_tenfold[9]);
    let sum = (3..digit_range_max)
        .filter(|&d| match_factorial_sum_10000(d, &factorial_sum_10000_fold)) 
        .sum::<u32>();

    println!("{}", sum);
    assert_eq!(sum, 40730);
}
Problem 35 "Circular primes"

The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.

There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97.

How many circular primes are there below one million?

問 35 「巡回素数」

197は巡回素数と呼ばれる. 桁を回転させたときに得られる数 197, 971, 719 が全て素数だからである.

100未満には巡回素数が13個ある: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, および97である.

100万未満の巡回素数はいくつあるか?

struct Sieve {
    _sieve: Vec<bool>,
}

impl Sieve {
    fn rule_out(&mut self, prime: usize) {
        for i in (prime * prime..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn init(&mut self) {
        let sqrt = (self._sieve.len() as f64).sqrt() as usize;
        let mut index = 5usize;
        for &i in [2usize, 4].iter().cycle() {
            if index > sqrt {
                break;
            }
            if self._sieve[index] {
                self.rule_out(index);
            }
            index += i;
        }
    }
    fn new(below: u32) -> Self {
        assert!(below > 4);
        let sieve = vec![true; below as usize];
        let mut s = Self { _sieve: sieve };
        s.init();
        s
    }
    fn is_prime(&self, n: u32) -> bool {
        assert!(n < self._sieve.len() as u32);
        if n == 2 || n == 3 {
            return true;
        }
        if n == 0 || n == 1 || n % 2 == 0 || n % 3 == 0 {
            return false;
        }
        self._sieve[n as usize]
    }
    fn primes(&self, below: u32) -> Vec<u32> {
        let mut primes: Vec<u32> = vec![2u32, 3u32];
        let mut index = 5usize;
        for &i in [2usize, 4].iter().cycle() {
            if index >= below as usize {
                break;
            }
            if self._sieve[index] {
                primes.push(index as u32);
            }
            index += i;
        }
        primes
    }
}

fn is_circular_prime(mut p: u32, sieve: &Sieve) -> bool {
    let log10 = (p as f32).log10();
    let exp10 = 10u32.pow(log10 as u32);
    for _ in 0..log10 as u8 {
        let d = p % 10;
        p /= 10;
        p += exp10 * d;
        if !sieve.is_prime(p) {
            return false;
        }
    }
    true
}

fn main() {
    let sieve = Sieve::new(1_000_000);
    let count = sieve
        .primes(1_000_000)
        .iter()
        .filter(|&p| is_circular_prime(*p, &sieve))
        .count();

    println!("{}", count);
    assert_eq!(count, 55);
}
Problem 36 "Double-base palindromes"

The decimal number, 585 = 10010010012 (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.)

問 36 「二種類の基数による回文数」

585 = 10010010012 (2進) は10進でも2進でも回文数である.

100万未満で10進でも2進でも回文数になるような数の総和を求めよ.

(注: 先頭に0を含めて回文にすることは許されない.)

fn generate_even_and_odd_palindromes(mut n: u32) -> (u32, u32) {
    let mut ep = n.clone();
    let mut op = n.clone();
    op /= 10;
    while n > 0 {
        ep *= 10;
        op *= 10;
        ep += n % 10;
        op += n % 10;
        n /= 10;
    }
    (ep, op)
}

fn is_double_based_palindrome(a: u32) -> bool {
    if a % 2 == 0 {
        return false;
    }
    let mut t = a.clone();
    let mut b = 0u32;
    while t > 0 {
        b <<= 1;
        b |= t & 1;
        t >>= 1;
    }
    a == b
}

fn main() {
    let mut sum = 0u32;
    let half = 10u32.pow(1_000_000f32.log10() as u32 / 2);
    for n in 1..half {
        let (ep, op) = generate_even_and_odd_palindromes(n);
        if is_double_based_palindrome(ep) {
            sum += ep;
        }
        if is_double_based_palindrome(op) {
            sum += op;
        }
    }

    println!("{}", sum);
    assert_eq!(sum, 872187);
}

fn is_palindrome(a: u32) -> bool {
    if a % 2 == 0 && a % 11 != 0 {
        return false;
    }
    let mut t = a.clone();
    let mut b = 0u32;
    while t > 0 {
        b *= 10;
        b += t % 10;
        t /= 10;
    }
    a == b
}

fn is_double_based_palindrome(a: u32) -> bool {
    if a % 2 == 0 {
        return false;
    }
    let mut t = a.clone();
    let mut b = 0u32;
    while t > 0 {
        b <<= 1;
        b |= t & 1;
        t >>= 1;
    }
    a == b
}

fn main() {
    let sum = (1..1_000_000)
        .step_by(2)
        .filter(|&n| is_palindrome(n))
        .filter(|&n| is_double_based_palindrome(n))
        .sum::<u32>();

    println!("{}", sum);
    assert_eq!(sum, 872187);
}
Problem 37 "Truncatable primes"

The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.

Find the sum of the only eleven primes that are both truncatable from left to right and right to left.

NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.

問 37 「切り詰め可能素数」

3797は面白い性質を持っている. まずそれ自身が素数であり, 左から右に桁を除いたときに全て素数になっている (3797, 797, 97, 7). 同様に右から左に桁を除いたときも全て素数である (3797, 379, 37, 3).

右から切り詰めても左から切り詰めても素数になるような素数は11個しかない. 総和を求めよ.

注: 2, 3, 5, 7を切り詰め可能な素数とは考えない.

fn is_prime(n: u32) -> bool {
    if n < 2 {
        return false;
    }
    if n == 2 || n == 3 || n == 5 {
        return true;
    }
    for d in &[2u32, 3, 5] {
        if n % *d == 0 {
            return false;
        }
    }
    let side = (n as f32).sqrt() as u32;
    let mut d = 5u32;
    for i in [2u32, 4].iter().cycle() {
        d += *i;
        if d > side {
            break;
        }
        if n % d == 0 {
            return false;
        }
    }
    true
}

fn generate_right_truncatable_maybe_prime_numbers(mut p: u32) -> (u32, u32, u32, u32) {
    p *= 10;
    (p + 1, p + 3, p + 7, p + 9)
}

fn is_left_trancatable_prime(p: u32) -> bool {
    let mut d = 10u32;
    while d < p {
        if !is_prime(p % d) {
            return false;
        }
        d *= 10;
    }
    true
}

fn expand_right_truncatable_prime(p: u32, left_truncatable_prime_sum: &mut u32) {
    if is_left_trancatable_prime(p) {
        *left_truncatable_prime_sum += p;
    }
    let (n1, n2, n3, n4) = generate_right_truncatable_maybe_prime_numbers(p);
    for &p in [n1, n2, n3, n4].iter().filter(|&n| is_prime(*n)) {
        expand_right_truncatable_prime(p, left_truncatable_prime_sum);
    }
}

fn main() {
    let mut left_truncatable_prime_sum = 0u32;
    for &p in [2u32, 3, 5, 7].iter() {
        expand_right_truncatable_prime(p, &mut left_truncatable_prime_sum);
    }

    println!("{}", left_truncatable_prime_sum - 2 - 3 - 5 - 7);
    assert_eq!(left_truncatable_prime_sum - 2 - 3 - 5 - 7, 748317);
}

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

struct Sieve {
    _sieve: Vec<bool>,
    _primes: Vec<usize>,
    _index: Index,
    _queue: std::collections::VecDeque<usize>,
}

impl Sieve {
    fn rule_out(&mut self, prime: usize) {
        for i in (prime * prime..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn rule_out_from_previous_position(&mut self, prime: usize, pp: usize) {
        use std::cmp::max;
        let begin = max((((pp - 1) / prime) + 1) * prime, prime * prime);
        for i in (begin..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn clean_sieve(&mut self) {
        let sqrt = ((self._sieve.len() - 1) as f32).sqrt() as usize;
        while self._index.i <= sqrt {
            if self._sieve[self._index.i] {
                self._primes.push(self._index.i);
                self._queue.push_back(self._index.i);
                self.rule_out(self._index.i);
            }
            self._index.increment();
        }
        while self._index.i < self._sieve.len() {
            if self._sieve[self._index.i] {
                self._primes.push(self._index.i);
                self._queue.push_back(self._index.i);
            }
            self._index.increment();
        }
    }
    fn new(below: u32) -> Self {
        assert!(below > 4);
        let sieve = vec![true; below as usize];
        let mut s = Self {
            _sieve: sieve,
            _primes: vec![],
            _index: Index::new(),
            _queue: std::collections::VecDeque::new(),
        };
        s._queue.push_back(2);
        s._queue.push_back(3);
        s.clean_sieve();
        s
    }
    fn extend(&mut self) {
        let previous_len = self._sieve.len();
        self._sieve.extend(vec![true; previous_len]);
        for &p in &self._primes.clone() {
            self.rule_out_from_previous_position(p, previous_len);
        }
        self.clean_sieve();
    }
    fn is_prime(&mut self, n: u32) -> bool {
        if n == 2 || n == 3 {
            return true;
        }
        if n == 0 || n == 1 || n % 2 == 0 || n % 3 == 0 {
            return false;
        }
        while n > self._sieve.len() as u32 - 1 {
            self.extend();
        }
        self._sieve[n as usize]
    }
    fn next_prime(&mut self) -> u32 {
        loop {
            if let Some(p) = self._queue.pop_front() {
                return p as u32;
            }
            self.extend();
        }
    }
    fn is_left_trancatable_prime(&mut self, p: u32) -> bool {
        let mut d = 10u32;
        while d < p {
            if !self.is_prime(p % d) {
                return false;
            }
            d *= 10;
        }
        true
    }
    fn is_right_trancatable_prime(&mut self, p: u32) -> bool {
        let mut d = 10u32;
        while d < p {
            if !self.is_prime(p / d) {
                return false;
            }
            d *= 10;
        }
        true
    }
}

fn main() {
    let mut sum = 0u32;
    let mut sieve = Sieve::new(10_000);
    let mut count = 0u8;
    while count < 15 {
        let p = sieve.next_prime();
        if !sieve.is_left_trancatable_prime(p) {
            continue;
        }
        if !sieve.is_right_trancatable_prime(p) {
            continue;
        }
        count += 1;
        sum += p;
    }

    println!("{}", sum - 2 - 3 - 5 - 7);
    assert_eq!(sum - 2 - 3 - 5 - 7, 748317);
}
Problem 38 "Pandigital multiples"

Take the number 192 and multiply it by each of 1, 2, and 3:

192 × 1 = 192
192 × 2 = 384
192 × 3 = 576

By concatenating each product we get the 1 to 9 pandigital, 192384576. We will call 192384576 the concatenated product of 192 and (1,2,3)

The same can be achieved by starting with 9 and multiplying by 1, 2, 3, 4, and 5, giving the pandigital, 918273645, which is the concatenated product of 9 and (1,2,3,4,5).

What is the largest 1 to 9 pandigital 9-digit number that can be formed as the concatenated product of an integer with (1,2, ... , n) where n > 1?

問 38 「パンデジタル倍数」

192 に 1, 2, 3 を掛けてみよう.

192 × 1 = 192 192 × 2 = 384 192 × 3 = 576

積を連結することで1から9の パンデジタル数 192384576 が得られる.

192384576 を 192 と (1,2,3) の連結積と呼ぶ.

同じようにして, 9 を 1,2,3,4,5 と掛け連結することでパンデジタル数 918273645 が得られる. これは 9 と (1,2,3,4,5) との連結積である.

整数と (1,2,..., n) (n; > 1) との連結積として得られる9桁のパンデジタル数の中で最大のものはいくつか?

fn is_pandigital(a: u32, b: u32) -> bool {
    let mut bits = 0u16;
    for n in [a, b].iter_mut() {
        while *n > 0 {
            let d = *n % 10;
            *n /= 10;
            bits |= 1 << d;
        }
    }
    bits == 0b1111111110u16
}

fn largest_pandigital_concatenated_product() -> u32 {
    for n in (9183..=(19000 / 2) as u32).rev() {
        if is_pandigital(n, n * 2) {
            return n * 100_000 + 2 * n;
        }
    }
    918_273_645
}

fn main() {
    let max = largest_pandigital_concatenated_product();

    println!("{}", max);
    assert_eq!(max, 932718654);
}
Problem 39 "Integer right triangles"

If p is the perimeter of a right angle triangle with integral length sides, {a,b,c}, there are exactly three solutions for p = 120.

{20,48,52}, {24,45,51}, {30,40,50}

For which value of p ≤ 1000, is the number of solutions maximised?

問 39 「整数の直角三角形」

辺の長さが \( {a,b,c} \) と整数の3つ組である直角三角形を考え, その周囲の長さを p とする. p = 120のときには3つの解が存在する:

{20,48,52}, {24,45,51}, {30,40,50}

p ≤ 1000 のとき解の数が最大になる p はいくつか?


fn gcd(mut a: usize, mut b: usize) -> usize {
    assert!(a != 0 && b != 0);
    while b != 0 {
        let r = a % b;
        a = b;
        b = r;
    }
    a
}

fn main() {
    let mut counts = [0u8; 1001];
    for p in (12..=1000).step_by(2) {
        for m in 2..=(((p - 2) / 2) as f32).sqrt() as usize {
            for n in ((if m % 2 == 0 { 1 } else { 2 })..m).step_by(2) {
                let a = m * m - n * n;
                let b = 2 * m * n;
                let c = m * m + n * n;
                if a + b + c == p && gcd(m, n) == 1 {
                    for k in (p..=1000).step_by(p) {
                        counts[k] += 1;
                    }
                }
            }
        }
    }
    let (p, _) = counts
        .iter()
        .enumerate()
        .reduce(|(ap, a), (bp, b)| if *a > *b { (ap, a) } else { (bp, b) })
        .unwrap();

    println!("{}", p);
    assert_eq!(p, 840);
}

fn main() {
    let mut counts = [0u8; 1001];
    for c in 3..=997 {
        let mut b = 2;
        while b < 1000 - c && b < c {
            let mut a = 1;
            while a <= 1000 - c - b && a < b {
                if c * c == b * b + a * a {
                    counts[c + b + a] += 1;
                }
                a += 1;
            }
            b += 1;
        }
    }
    let (p, _) = counts
        .iter()
        .enumerate()
        .reduce(|(ap, a), (bp, b)| if *a > *b { (ap, a) } else { (bp, b) })
        .unwrap();

    println!("{}", p);
    assert_eq!(p, 840);
}
Problem 40 "Champernowne's constant"

An irrational decimal fraction is created by concatenating the positive integers:

0.123456789101112131415161718192021...

It can be seen that the 12th digit of the fractional part is 1.

If dn represents the nth digit of the fractional part, find the value of the following expression.

d1 × d10 × d100 × d1000 × d10000 × d100000 × d1000000

問 40 「チャンパーノウン定数」

正の整数を順に連結して得られる以下の10進の無理数を考える:

0.123456789101112131415161718192021...

小数第12位は1である.

dnで小数第n位の数を表す. \( d_{1} × d_{10} × d_{100} × d_{1000} × d_{10000} × d_{100000} × d_{1000000} \) を求めよ.

struct Container {
    capacity: u32,
    elements: u32,
}

fn digit_at(nth: u32) -> u8 {
    let mut container = Container {
        capacity: 0,
        elements: 0,
    };
    let mut w = 1u32;
    loop {
        let elements = 10u32.pow(w) - 10u32.pow(w - 1);
        let capacity = w * elements;
        if nth < container.capacity + capacity {
            break;
        }
        container.capacity += capacity;
        container.elements += elements;
        w += 1;
    }
    let residue = nth - container.capacity;
    if residue % w == 0 {
        return ((container.elements + residue / w) % 10) as u8;
    }
    let num = container.elements + residue / w + 1;
    ((num / 10u32.pow(w - residue % w)) % 10) as u8
}

fn main() {
    let p = (0u32..=6)
        .map(|d| 10u32.pow(d))
        .map(|d| digit_at(d))
        .map(|d| d as u32)
        .product::<u32>();

    println!("{}", p);
    assert_eq!(p, 210);

    assert_eq!(digit_at(1), 1);
    assert_eq!(digit_at(9), 9);
    assert_eq!(digit_at(17), 3);
    assert_eq!(digit_at(18), 1);
    assert_eq!(digit_at(189), 9);
    assert_eq!(digit_at(190), 1);
    assert_eq!(digit_at(194), 0);
    assert_eq!(digit_at(37371), 6);
}
Problem 41 "Pandigital prime"

We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly once. For example, 2143 is a 4-digit pandigital and is also prime.

What is the largest n-digit pandigital prime that exists?

問 41 「パンデジタル素数」

n桁パンデジタルであるとは, 1からnまでの数を各桁に1つずつ持つこととする. #下のリンク先にあるような数学的定義とは異なる

例えば2143は4桁 パンデジタル数 であり, かつ素数である.

n桁(この問題の定義では9桁以下)パンデジタルな素数の中で最大の数を答えよ.

fn consume(usable_items: &Vec<u32>, accumulated_num: u32, drain: &mut Vec<u32>) {
    if usable_items.len() == 0 {
        drain.push(accumulated_num);
        return;
    }
    for i in 0..usable_items.len() {
        let mut items = usable_items.clone();
        let mut num = accumulated_num.clone();
        let n = items.remove(i);
        num *= 10;
        num += n;
        consume(&items, num, drain);
    }
}

fn permutations(n: u32) -> Vec<u32> {
    let items = (1..=n).into_iter().rev().collect::<Vec<u32>>();
    let capacity = items.iter().map(|&i| i).product::<u32>() as usize;
    let mut drain = Vec::with_capacity(capacity);
    consume(&items, 0, &mut drain);
    drain
}

fn is_prime(n: u32) -> bool {
    if n < 2 {
        return false;
    }
    if n == 2 || n == 3 || n == 5 {
        return true;
    }
    for d in &[2u32, 3, 5] {
        if n % *d == 0 {
            return false;
        }
    }
    let side = (n as f32).sqrt() as u32;
    let mut d = 5u32;
    for i in [2u32, 4].iter().cycle() {
        d += *i;
        if d > side {
            break;
        }
        if n % d == 0 {
            return false;
        }
    }
    true
}

fn main() {
    let mut p = None;
    'exploration: for &d in [7, 4].iter() {
        for n in permutations(d) {
            if is_prime(n) {
                p = Some(n);
                break 'exploration;
            }
        }
    }

    println!("{:?}", p);
    assert_eq!(p, Some(7652413));
}
Problem 42 "Coded triangle numbers"

The nth term of the sequence of triangle numbers is given by, tn = ½n(n+1); so the first ten triangle numbers are:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

By converting each letter in a word to a number corresponding to its alphabetical position and adding these values we form a word value. For example, the word value for SKY is 19 + 11 + 25 = 55 = t10. If the word value is a triangle number then we shall call the word a triangle word.

Using words.txt, a 16K text file containing nearly two-thousand common English words, how many are triangle words?

問 42 「符号化三角数」

三角数のn項は \( t_{n} = n(n+1)/2 \) で与えられる. 最初の10項は

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

である.

単語中のアルファベットを数値に変換した後に和をとる. この和を「単語の値」と呼ぶことにする. 例えば SKY は 19 + 11 + 25 = 55 = \( t_{10} \) である. 単語の値が三角数であるとき, その単語を三角語と呼ぶ.

16Kのテキストファイル words.txt 中に約2000語の英単語が記されている. 三角語はいくつあるか?

Because the original word list is very long, this example has only a part of it.

fn is_triangle_number(x: u32) -> bool {
    let expr = 8 * x + 1;
    let side = (expr as f64).sqrt() as u32;
    side * side == expr
}

fn word_value(w: &str) -> u32 {
    w.chars().map(|c| c as u32 - 'A' as u32 + 1).sum::<u32>()
}

fn main() {
    let count = WORDS
        .iter()
        .map(|&w| word_value(w))
        .filter(|&v| is_triangle_number(v))
        .count();

    println!("{:?}", count);
    assert_eq!(count, 5);
}

const WORDS: &[&str] = &[
    "A",
    "ABILITY",
    "ABLE",
    "ABOUT",
    "ABOVE",
    "ABSENCE",
    "ABSOLUTELY",
    "ACADEMIC",
    "ACCEPT",
    "ACCESS",
    "ACCIDENT",
    "ACCOMPANY",
    "ACCORDING",
    "ACCOUNT",
    "ACHIEVE",
    "ACHIEVEMENT",
    "ACID"
];
Problem 43 "Sub-string divisibility"

The number, 1406357289, is a 0 to 9 pandigital number because it is made up of each of the digits 0 to 9 in some order, but it also has a rather interesting sub-string divisibility property.

Let d1 be the 1st digit, d2 be the 2nd digit, and so on. In this way, we note the following:

  • d2d3d4=406 is divisible by 2
  • d3d4d5=063 is divisible by 3
  • d4d5d6=635 is divisible by 5
  • d5d6d7=357 is divisible by 7
  • d6d7d8=572 is divisible by 11
  • d7d8d9=728 is divisible by 13
  • d8d9d10=289 is divisible by 17

Find the sum of all 0 to 9 pandigital numbers with this property.

問 43 「部分文字列被整除性」

数1406357289は0から9のパンデジタル数である (0から9が1度ずつ現れるので). この数は部分文字列が面白い性質を持っている.

\( d_{1} \) を上位1桁目, \( d_{2} \)を上位2桁目の数とし, 以下順に \( d_{n} \) を定義する. この記法を用いると次のことが分かる.

  • d2d3d4=406 は 2で割り切れる
  • d3d4d5=063 は 3で割り切れる
  • d4d5d6=635 は 5で割り切れる
  • d5d6d7=357 は 7で割り切れる
  • d6d7d8=572 は 11で割り切れる
  • d7d8d9=728 は 13で割り切れる
  • d8d9d10=289 は 17で割り切れる

このような性質をもつ0から9のパンデジタル数の総和を求めよ.

fn is_divisible(n: u64, depth: u8) -> bool {
    if depth < 2 || depth == 9 {
        return true;
    }
    let p = match depth {
        2 => 17,
        3 => 13,
        4 => 11,
        5 => 7,
        6 => 5,
        7 => 3,
        8 => 2,
        _ => unreachable!(),
    };
    (n / 10u64.pow(depth as u32 - 2)) % p == 0
}

fn consume(
    usable_items: &Vec<u8>,
    accumulated_num: u64,
    drain: &mut Vec<u64>,
    depth: u8,
) {
    if usable_items.len() == 0 {
        drain.push(accumulated_num);
        return;
    }
    for i in 0..usable_items.len() {
        let mut items = usable_items.clone();
        let mut num = accumulated_num.clone();
        let n = items.remove(i);
        let weight = 10u64.pow(depth as u32);
        num += weight * n as u64;
        if !is_divisible(num, depth) {
            continue;
        }
        consume(&items, num, drain, depth + 1);
    }
}

fn permutations_with_conditions() -> Vec<u64> {
    let items = (0..=9).into_iter().collect::<Vec<u8>>();
    let mut drain = vec![];
    consume(&items, 0, &mut drain, 0);
    drain
}

fn main() {
    let sum = permutations_with_conditions()
        .iter()
        .filter(|&n| *n > 999_999_999)
        .sum::<u64>();

    println!("{}", sum);
    assert_eq!(sum, 16695334890);
}

fn is_divisible(n: u64, depth: u8) -> bool {
    if depth < 3 {
        return true;
    }
    let p = match depth {
        3 => 2,
        4 => 3,
        5 => 5,
        6 => 7,
        7 => 11,
        8 => 13,
        9 => 17,
        _ => unreachable!(),
    };
    (n % 1000) % p == 0
}

fn consume(
    usable_items: &Vec<u8>,
    accumulated_num: u64,
    drain: &mut Vec<u64>,
    depth: u8,
) {
    if usable_items.len() == 0 {
        drain.push(accumulated_num);
        return;
    }
    for i in 0..usable_items.len() {
        let mut items = usable_items.clone();
        let mut num = accumulated_num.clone();
        let n = items.remove(i);
        num *= 10;
        num += n as u64;
        if !is_divisible(num, depth) {
            continue;
        }
        consume(&items, num, drain, depth + 1);
    }
}

fn permutations_with_conditions() -> Vec<u64> {
    let items = (0..=9).into_iter().collect::<Vec<u8>>();
    let mut drain = vec![];
    consume(&items, 0, &mut drain, 0);
    drain
}

fn main() {
    let sum = permutations_with_conditions()
        .iter()
        .filter(|&n| *n > 999_999_999)
        .sum::<u64>();

    println!("{}", sum);
    assert_eq!(sum, 16695334890);
}
Problem 44 "Pentagon numbers"

Pentagonal numbers are generated by the formula, Pn=n(3n−1)/2. The first ten pentagonal numbers are:

1, 5, 12, 22, 35, 51, 70, 92, 117, 145, ...

It can be seen that P4 + P7 = 22 + 70 = 92 = P8. However, their difference, 70 − 22 = 48, is not pentagonal.

Find the pair of pentagonal numbers, Pj and Pk, for which their sum and difference are pentagonal and D = |Pk − Pj| is minimised; what is the value of D?

問 44 「五角数」

五角数は \(P_{n} = n(3n-1)/2 \) で生成される. 最初の10項は

1, 5, 12, 22, 35, 51, 70, 92, 117, 145, ...

である.

\( P_{4} + P_{7} = 22 + 70 = 92 = P_{8} \) である. しかし差 70 - 22 = 48 は五角数ではない.

五角数のペア \( P_{j} \) と \( P_{k} \) について, 差と和が五角数になるものを考える. 差を D = \( |P_{k} - P_{j}| \) と書く. 差 D の最小値を求めよ.

fn is_pentagonal(n: u64) -> bool {
    let expr = 24 * n + 1;
    let sqrt = (expr as f64).sqrt() as u64;
    if expr != sqrt * sqrt {
        return false;
    }
    sqrt % 6 == 5
}

fn pentagon(n: u64) -> u64 {
    n * (3 * n - 1) / 2
}

fn calc_distance(pentagons: &mut Vec<u64>) -> (u64, u64) {
    for n in 1u64.. {
        let p1 = pentagon(n);
        for &p2 in pentagons.iter().rev() {
            let d = p1 - p2;
            let s = p1 + p2;
            if is_pentagonal(d) && is_pentagonal(s) {
                return (d, n);
            }
        }
        pentagons.push(p1);
    }
    unreachable!("This function is supposed to have return but not break in the outermost loop!");
}

fn is_answer_confirmed(pentagons: &mut Vec<u64>, distance: u64, nth: u64) -> bool {
    pentagons.push(pentagon(nth));
    for n in nth + 1.. {
        let p1 = pentagon(n);
        if 3 * (n - 1) + 1 > distance {
            return true;
        }
        for &p2 in pentagons.iter().rev() {
            let d = p1 - p2;
            if d >= distance {
                break;
            }
            let s = p1 + p2;
            if is_pentagonal(d) && is_pentagonal(s) {
                return false;
            }
        }
        pentagons.push(p1);
    }
    unreachable!("This function is supposed to have return but not break in the outermost loop!");
}

fn main() {
    let mut pentagons = vec![];
    let (d, nth) = calc_distance(&mut pentagons);
    assert!(is_answer_confirmed(&mut pentagons, d, nth));

    println!("{}", d);
    assert_eq!(d, 5482660);
}
Problem 45 "Triangular, pentagonal, and hexagonal"

Triangle, pentagonal, and hexagonal numbers are generated by the following formulae:

Triangle Tn=n(n+1)/2 1, 3, 6, 10, 15, ...
Pentagonal Pn=n(3n−1)/2 1, 5, 12, 22, 35, ...
Hexagonal Hn=n(2n−1) 1, 6, 15, 28, 45, ...

It can be verified that T285 = P165 = H143 = 40755.

Find the next triangle number that is also pentagonal and hexagonal.

問 45 「三角数, 五角数, 六角数」

三角数, 五角数, 六角数は以下のように生成される.

T285 = P165 = H143 = 40755 であることが分かる.

次の三角数かつ五角数かつ六角数な数を求めよ.

struct Pentagon {
    n: u64,
    v: u64,
}

impl Pentagon {
    fn increment(&mut self) {
        self.v += self.n * 3 + 1;
        self.n += 1;
    }
    fn value(&self) -> u64 {
        self.v
    }
}

struct Hexagon {
    n: u64,
    v: u64,
}

impl Hexagon {
    fn increment(&mut self) {
        self.v += 4 * self.n + 1;
        self.n += 1;
    }
    fn value(&self) -> u64 {
        self.v
    }
}

fn main() {
    let mut p = Pentagon { n: 165, v: 40755 };
    let mut h = Hexagon { n: 143, v: 40755 };
    p.increment();
    let v = loop {
        while p.value() < h.value() {
            p.increment();
        }
        while h.value() < p.value() {
            h.increment();
        }
        if p.value() == h.value() {
            break p.value();
        }
    };

    println!("{}", v);
    assert_eq!(v, 1533776805);
}
Problem 46 "Goldbach's other conjecture"

It was proposed by Christian Goldbach that every odd composite number can be written as the sum of a prime and twice a square.

9 = 7 + 2×12
15 = 7 + 2×22
21 = 3 + 2×32
25 = 7 + 2×32
27 = 19 + 2×22
33 = 31 + 2×12

It turns out that the conjecture was false.

What is the smallest odd composite that cannot be written as the sum of a prime and twice a square?

問 46 「もうひとつのゴールドバッハの予想」

Christian Goldbachは全ての奇合成数は平方数の2倍と素数の和で表せると予想した.

後に, この予想は誤りであることが分かった.

平方数の2倍と素数の和で表せない最小の奇合成数はいくつか?

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

struct Sieve {
    _sieve: Vec<bool>,
    _primes: Vec<usize>,
    _index: Index,
}

impl Sieve {
    fn rule_out(&mut self, prime: usize) {
        for i in (prime * prime..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn clean_sieve(&mut self) {
        let sqrt = (self._sieve.len() as f32).sqrt() as usize;
        while self._index.i <= sqrt {
            if self._sieve[self._index.i] {
                self._primes.push(self._index.i);
                self.rule_out(self._index.i);
            }
            self._index.increment();
        }
        while self._index.i < self._sieve.len() {
            if self._sieve[self._index.i] {
                self._primes.push(self._index.i);
            }
            self._index.increment();
        }
    }
    fn new(below: u32) -> Self {
        assert!(below > 4);
        let sieve = vec![true; below as usize];
        let mut s = Self {
            _sieve: sieve,
            _primes: vec![],
            _index: Index::new(),
        };
        s.clean_sieve();
        s
    }
    fn extend(&mut self) {
        self._sieve.extend(vec![true; self._sieve.len()]);
        let primes = self._primes.clone();
        for &p in primes.iter() {
            self.rule_out(p);
        }
        self.clean_sieve();
    }
    fn is_prime(&mut self, n: u32) -> bool {
        if n == 2 || n == 3 {
            return true;
        }
        if n == 0 || n == 1 || n % 2 == 0 || n % 3 == 0 {
            return false;
        }
        while n > self._sieve.len() as u32 - 1 {
            self.extend();
        }
        self._sieve[n as usize]
    }
}

struct DoubleSquares {
    _n: u32,
    _elements: Vec<u32>,
}

impl DoubleSquares {
    fn new() -> Self {
        Self {
            _n: 5,
            _elements: vec![2, 8, 18, 32, 50],
        }
    }
    fn extend(&mut self) {
        for n in self._n + 1..self._n * 2 {
            self._elements.push(n * n * 2);
        }
        self._n *= 2;
    }
    fn double_check(&mut self, sieve: &mut Sieve, o: u32) -> Result<(), ()> {
        while o > self._elements.last().map(|&n| n).unwrap_or(0) {
            self.extend();
        }
        for &d in &self._elements {
            if d >= o {
                return Err(());
            }
            if sieve.is_prime(o - d) {
                return Ok(());
            }
        }
        panic!("This function is supposed to have return but not break in loop!");
    }
}

fn explore_error_value() -> u32 {
    let mut sieve = Sieve::new(1000);
    let mut double_squares = DoubleSquares::new();
    for o in (9..).step_by(2) {
        if sieve.is_prime(o) {
            continue;
        }
        if double_squares.double_check(&mut sieve, o).is_err() {
            return o;
        }
    }
    unreachable!("This function is supposed to have return but not break in loop!");
}

fn main() {
    let e = explore_error_value();
    println!("{}", e);
    assert_eq!(e, 5777);
}
Problem 47 "Distinct primes factors"

The first two consecutive numbers to have two distinct prime factors are:

14 = 2 × 7
15 = 3 × 5

The first three consecutive numbers to have three distinct prime factors are:

644 = 2² × 7 × 23
645 = 3 × 5 × 43
646 = 2 × 17 × 19.

Find the first four consecutive integers to have four distinct prime factors each. What is the first of these numbers?

問 47 「異なる素因数」

それぞれ2つの異なる素因数を持つ連続する2つの数が最初に現れるのは:

14 = 2 × 7

15 = 3 × 5

それぞれ3つの異なる素因数を持つ連続する3つの数が最初に現れるのは:

644 = 22 × 7 × 23

645 = 3 × 5 × 43

646 = 2 × 17 × 19

最初に現れるそれぞれ4つの異なる素因数を持つ連続する4つの数を求めよ. その最初の数はいくつか?

struct Sieve {
    _sieve: Vec<bool>,
    _count: Vec<u8>,
    _primes: Vec<usize>,
    _cursor: usize,
}

impl Sieve {
    fn rule_out(&mut self, prime: usize) {
        for i in (prime..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
            self._count[i] += 1;
        }
    }
    fn rule_out_from_previous_position(&mut self, prime: usize, pp: usize) {
        let begin = (((pp - 1) / prime) + 1) * prime;
        for i in (begin..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
            self._count[i] += 1;
        }
    }
    fn is_start_of_four_consective_nums_with_factors(&self) -> bool {
        let i = self._cursor;
        if self._count[i] != 4 {
            return false;
        }
        if self._count.len() - 1 < i + 3 {
            return false;
        }
        self._count[i + 1] == 4 && self._count[i + 2] == 4 && self._count[i + 3] == 4
    }
    fn clean_sieve_with_exploration(&mut self) -> Option<u32> {
        while self._cursor < self._sieve.len() {
            if self._sieve[self._cursor] {
                self._primes.push(self._cursor);
                self.rule_out(self._cursor);
                continue;
            }
            if self.is_start_of_four_consective_nums_with_factors() {
                return Some(self._cursor as u32);
            }
            self._cursor += 1;
        }
        None
    }
    fn new(below: u32) -> Self {
        assert!(below > 4);
        let sieve = vec![true; below as usize];
        let count = vec![0u8; below as usize];
        Self {
            _sieve: sieve,
            _count: count,
            _primes: vec![],
            _cursor: 2,
        }
    }
    fn extend(&mut self) {
        let prev_len = self._sieve.len();
        self._sieve.extend(vec![true; self._sieve.len()]);
        self._count.extend(vec![0u8; self._count.len()]);
        let primes = self._primes.clone();
        for &p in primes.iter() {
            self.rule_out_from_previous_position(p, prev_len);
        }
    }
}

fn main() {
    let mut sieve = Sieve::new(10_000);
    let n = loop {
        if let Some(n) = sieve.clean_sieve_with_exploration() {
            break n;
        }
        sieve.extend();
    };

    println!("{}", n);
    assert_eq!(n, 134043);
}
Problem 48 "Self powers"

The series, 11 + 22 + 33 + ... + 1010 = 10405071317.

Find the last ten digits of the series, 11 + 22 + 33 + ... + 10001000.

問 48 「自身のべき乗」

11 + 22 + 33 + ... + 1010 = 10405071317.

11 + 22 + 33 + ... + 10001000 の最後の10桁を求めよ.

fn conservative_mod_pow(a: u64, exp: u64, m: u64) -> u64 {
    let mut result = 1;
    for _ in 0..exp {
        result *= a;
        result %= m;
    }
    result
}

fn main() {
    let m = 10_000_000_000;
    let mut sum = 0u64;
    for n in 1..=1000 {
        sum += conservative_mod_pow(n, n, m);
        sum %= m;
    }

    println!("{}", sum);
    assert_eq!(sum, 9110846700);
}

fn mod_pow(a: u64, exp: u64, m: u64) -> u64 {
    let (mut a, mut exp, m) = (a as u128, exp as u128, m as u128);
    if m == 1 {
        return 0;
    }
    if exp == 0 {
        return 1;
    }
    let mut result = 1;
    a %= m;
    loop {
        if exp % 2 == 1 {
            result *= a;
            result %= m;
        }
        exp >>= 1;
        if exp == 0 {
            break;
        }
        a *= a;
        a %= m;
    }
    result as u64
}

fn main() {
    let m = 10_000_000_000u64;
    let mut sum = 0u64;
    for n in 1..=1000 {
        sum += mod_pow(n, n, m);
        sum %= m;
    }

    println!("{}", sum);
    assert_eq!(sum, 9110846700);
}
Problem 49 "Prime permutations"

The arithmetic sequence, 1487, 4817, 8147, in which each of the terms increases by 3330, is unusual in two ways: (i) each of the three terms are prime, and, (ii) each of the 4-digit numbers are permutations of one another.

There are no arithmetic sequences made up of three 1-, 2-, or 3-digit primes, exhibiting this property, but there is one other 4-digit increasing sequence.

What 12-digit number do you form by concatenating the three terms in this sequence?

問 49 「素数数列」

  1. 3つの項はそれぞれ素数である.
  2. 各項は他の項の置換で表される.

1, 2, 3桁の素数にはこのような性質を持った数列は存在しないが, 4桁の増加列にはもう1つ存在する.

それではこの数列の3つの項を連結した12桁の数を求めよ.

struct Sieve {
    _sieve: Vec<bool>,
}

impl Sieve {
    fn rule_out(&mut self, prime: usize) {
        for i in (prime * prime..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn init(&mut self) {
        let sqrt = (self._sieve.len() as f64).sqrt() as usize;
        let mut index = 5usize;
        for &i in [2usize, 4].iter().cycle() {
            if index > sqrt {
                break;
            }
            if self._sieve[index] {
                self.rule_out(index);
            }
            index += i;
        }
    }
    fn new(below: u32) -> Self {
        assert!(below > 4);
        let sieve = vec![true; below as usize];
        let mut s = Self { _sieve: sieve };
        s.init();
        s
    }
    fn is_prime(&self, n: u32) -> bool {
        assert!(n < self._sieve.len() as u32);
        if n == 2 || n == 3 {
            return true;
        }
        if n == 0 || n == 1 || n % 2 == 0 || n % 3 == 0 {
            return false;
        }
        self._sieve[n as usize]
    }
    fn primes(&self, below: u32) -> Vec<u32> {
        let mut primes: Vec<u32> = vec![2u32, 3u32];
        let mut index = 5usize;
        for &i in [2usize, 4].iter().cycle() {
            if index >= below as usize {
                break;
            }
            if self._sieve[index] {
                primes.push(index as u32);
            }
            index += i;
        }
        primes
    }
}

fn is_permutations(mut a: u32, mut b: u32, mut c: u32) -> bool {
    assert!(a > 999 && b > 999 && c > 999);
    assert!(a < 10000 && b < 10000 && c < 10000);
    for n in [&mut a, &mut b, &mut c].iter_mut() {
        **n *= 10;
        **n += 1;
    }
    let (mut a_bits, mut b_bits, mut c_bits) = (0u16, 0u16, 0u16);
    for (n, bits) in [
        (&mut a, &mut a_bits),
        (&mut b, &mut b_bits),
        (&mut c, &mut c_bits),
    ]
    .iter_mut()
    {
        while **n > 1 {
            let d = **n % 10;
            **n /= 10;
            **bits |= 1 << d;
        }
    }
    a_bits == b_bits && b_bits == c_bits
}

fn main() {
    let sieve = Sieve::new(10_000);
    let series = sieve
        .primes(10_000)
        .iter()
        .filter(|&p| *p > 999 && *p < 10_000 - 6660)
        .filter(|&p| sieve.is_prime(*p + 3330) && sieve.is_prime(*p + 6660))
        .filter(|&p| *p != 1487)
        .filter(|&p| is_permutations(*p, *p + 3330, *p + 6660))
        .map(|&p| p as u64)
        .map(|p| p * 100_000_000 + (p + 3330) * 10_000 + p + 6660)
        .last()
        .expect("The prime series with a difference of 3330 not found!");

    println!("{}", series);
    assert_eq!(series, 296962999629);
}
Problem 50 "Consecutive prime sum"

The prime 41, can be written as the sum of six consecutive primes:

41 = 2 + 3 + 5 + 7 + 11 + 13

This is the longest sum of consecutive primes that adds to a prime below one-hundred.

The longest sum of consecutive primes below one-thousand that adds to a prime, contains 21 terms, and is equal to 953.

Which prime, below one-million, can be written as the sum of the most consecutive primes?

問 50 「連続する素数の和」

素数41は6つの連続する素数の和として表せる:

41 = 2 + 3 + 5 + 7 + 11 + 13.

100未満の素数を連続する素数の和で表したときにこれが最長になる.

同様に, 連続する素数の和で1000未満の素数を表したときに最長になるのは953で21項を持つ.

100万未満の素数を連続する素数の和で表したときに最長になるのはどの素数か?

fn mod_pow(a: u32, exp: u32, m: u32) -> u32 {
    let (mut a, mut exp, m) = (a as u64, exp as u64, m as u64);
    if m == 1 {
        return 0;
    }
    if exp == 0 {
        return 1;
    }
    let mut result = 1;
    a %= m;
    loop {
        if exp % 2 == 1 {
            result *= a;
            result %= m;
        }
        exp >>= 1;
        if exp == 0 {
            break;
        }
        a *= a;
        a %= m;
    }
    result as u32
}

fn gcd(mut a: u32, mut b: u32) -> u32 {
    assert!(a != 0 && b != 0);
    while b != 0 {
        let r = a % b;
        a = b;
        b = r;
    }
    a
}

fn pseudo_fermat_test(n: u32) -> bool {
    gcd(223092870, n) == 1 && mod_pow(223092870, n - 1, n) == 1
}

fn rule_out(sieve: &mut Vec<bool>, prime: usize) {
    for i in (prime * prime..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn rule_out_from_previous_position(sieve: &mut Vec<bool>, prime: usize, pp: usize) {
    use std::cmp::max;
    let begin = max((((pp - 1) / prime) + 1) * prime, prime * prime);
    for i in (begin..sieve.len()).step_by(prime) {
        sieve[i] = false;
    }
}

fn extend(sieve: &mut Vec<bool>, primes: &Vec<usize>) {
    let previous_len = sieve.len();
    sieve.extend(vec![true; previous_len]);
    for &p in primes {
        rule_out_from_previous_position(sieve, p, previous_len);
    }
}

fn main() {
    let mut sum = 2u32 + 3;
    let mut sieve = vec![true; 1000];
    let mut primes: Vec<usize> = vec![];
    let mut cursor = 5usize;
    let mut ite = [2usize, 4].iter().cycle();
    'sum_fill: loop {
        while cursor < sieve.len() {
            if !sieve[cursor] {
                cursor += ite.next().unwrap();
                continue;
            }
            &primes.push(cursor);
            rule_out(&mut sieve, cursor);
            sum += cursor as u32;
            if sum >= 1_000_000 {
                sum -= cursor as u32;
                break 'sum_fill;
            }
            cursor += ite.next().unwrap();
        }
        extend(&mut sieve, &primes);
    }

    primes.insert(0, 2);
    primes.insert(1, 3);
    for p in primes {
        sum -= p as u32;
        if pseudo_fermat_test(sum) {
            break;
        }
    }

    println!("{}", sum);
    assert_eq!(sum, 997651);
}

struct Sieve {
    _sieve: Vec<bool>,
}

impl Sieve {
    fn rule_out(&mut self, prime: usize) {
        for i in (prime * prime..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn init(&mut self) {
        let sqrt = (self._sieve.len() as f64).sqrt() as usize;
        let mut index = 5usize;
        for &i in [2usize, 4].iter().cycle() {
            if index > sqrt {
                break;
            }
            if self._sieve[index] {
                self.rule_out(index);
            }
            index += i;
        }
    }
    fn new(below: u32) -> Self {
        assert!(below > 4);
        let sieve = vec![true; below as usize];
        let mut s = Self { _sieve: sieve };
        s.init();
        s
    }
    fn is_prime(&self, n: u32) -> bool {
        assert!(n < self._sieve.len() as u32);
        if n == 2 || n == 3 {
            return true;
        }
        if n == 0 || n == 1 || n % 2 == 0 || n % 3 == 0 {
            return false;
        }
        self._sieve[n as usize]
    }
    fn primes(&self, below: u32) -> Vec<u32> {
        let mut primes = vec![2u32, 3u32];
        let mut index = 5usize;
        for &i in [2usize, 4].iter().cycle() {
            if index >= below as usize {
                break;
            }
            if self._sieve[index] {
                primes.push(index as u32);
            }
            index += i;
        }
        primes
    }
}

fn fill_sum_up_to_million(primes: &[u32]) -> u32 {
    let mut sum = 0u32;
    for &p in primes {
        sum += p;
        if sum > 1_000_000 {
            sum -= p;
            return sum;
        }
    }
    panic!("The prime list was not enough to fill up the sum to be 1 million!");
}

fn main() {
    let sieve = Sieve::new(1_000_000);
    let primes = sieve.primes(1_000_000);
    let mut sum = fill_sum_up_to_million(&primes);
    for p in primes {
        sum -= p;
        if sieve.is_prime(sum) {
            break;
        }
    }

    println!("{}", sum);
    assert_eq!(sum, 997651);
}
Problem 51 "Prime digit replacements"

By replacing the 1st digit of the 2-digit number *3, it turns out that six of the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime.

By replacing the 3rd and 4th digits of 56**3 with the same digit, this 5-digit number is the first example having seven primes among the ten generated numbers, yielding the family: 56003, 56113, 56333, 56443, 56663, 56773, and 56993. Consequently 56003, being the first member of this family, is the smallest prime with this property.

Find the smallest prime which, by replacing part of the number (not necessarily adjacent digits) with the same digit, is part of an eight prime value family.

問 51 「素数の桁置換」

*3の第1桁を置き換えることで, 13, 23, 43, 53, 73, 83という6つの素数が得られる.

56**3の第3桁と第4桁を同じ数で置き換えることを考えよう. この5桁の数は7つの素数をもつ最初の例である: 56003, 56113, 56333, 56443, 56663, 56773, 56993. よって, この族の最初の数である56003は, このような性質を持つ最小の素数である.

桁を同じ数で置き換えることで8つの素数が得られる最小の素数を求めよ. (注:連続した桁でなくても良い)

struct Index {
    i: usize,
    _ite: Box<dyn Iterator<Item = usize>>,
}

impl Index {
    fn increment(&mut self) {
        self.i += self._ite.next().unwrap();
    }
    fn new() -> Self {
        Self {
            i: 5,
            _ite: Box::new(vec![2usize, 4].into_iter().cycle()),
        }
    }
}

struct Sieve {
    _sieve: Vec<bool>,
    _primes: Vec<usize>,
    _index: Index,
    _queue: std::collections::VecDeque<usize>,
}

impl Sieve {
    fn rule_out(&mut self, prime: usize) {
        for i in (prime * prime..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn rule_out_from_previous_position(&mut self, prime: usize, pp: usize) {
        use std::cmp::max;
        let begin = max((((pp - 1) / prime) + 1) * prime, prime * prime);
        for i in (begin..self._sieve.len()).step_by(prime) {
            self._sieve[i] = false;
        }
    }
    fn clean_sieve(&mut self) {
        let sqrt = (self._sieve.len() as f32).sqrt() as usize;
        while self._index.i <= sqrt {
            if self._sieve[self._index.i] {
                self._primes.push(self._index.i);
                self._queue.push_back(self._index.i);
                self.rule_out(self._index.i);
            }
            self._index.increment();
        }
        while self._index.i < self._sieve.len() {
            if self._sieve[self._index.i] {
                self._primes.push(self._index.i);
                self._queue.push_back(self._index.i);
            }
            self._index.increment();
        }
    }
    fn new(below: u32) -> Self {
        assert!(below > 4);
        let sieve = vec![true; below as usize];
        let mut s = Self {
            _sieve: sieve,
            _primes: vec![],
            _index: Index::new(),
            _queue: std::collections::VecDeque::new(),
        };
        s._queue.push_back(2);
        s._queue.push_back(3);
        s.clean_sieve();
        s
    }
    fn extend(&mut self) {
        let previous_len = self._sieve.len();
        self._sieve.extend(vec![true; previous_len]);
        for &p in &self._primes.clone() {
            self.rule_out_from_previous_position(p, previous_len);
        }
        self.clean_sieve();
    }
    fn is_prime(&mut self, n: u32) -> bool {
        if n == 2 || n == 3 {
            return true;
        }
        if n == 0 || n == 1 || n % 2 == 0 || n % 3 == 0 {
            return false;
        }
        while n > self._sieve.len() as u32 - 1 {
            self.extend();
        }
        self._sieve[n as usize]
    }
    fn next_prime(&mut self) -> u32 {
        loop {
            if let Some(p) = self._queue.pop_front() {
                return p as u32;
            }
            self.extend();
        }
    }
}

fn appearance_frequency_excluding_tail(mut p: u32, frequency: &mut Frequency) {
    frequency.clear();
    p /= 10;
    while p > 0 {
        let d = p % 10;
        frequency.0[d as usize] += 1;
        p /= 10;
    }
}

fn expand_wildcard(mut p: u32, wildcard: u8, expansion: &mut WildcardExpansion) {
    expansion.clear();
    let mut dicimal_place = 1u32;
    let first_digit = p % 10;
    for n in &mut expansion.0 {
        *n += first_digit;
    }
    p /= 10;
    while p > 0 {
        dicimal_place *= 10;
        let d = (p % 10) as u8;
        let is_wildcard = d as u8 == wildcard;
        for (i, n) in expansion.0.iter_mut().enumerate() {
            *n += dicimal_place * if is_wildcard { i as u32 } else { d as u32 };
        }
        p /= 10;
    }
}

fn digit_len_match(mut a: u32, mut b: u32) -> bool {
    while a > 0 && b > 0 {
        a /= 10;
        b /= 10;
    }
    a == b
}

struct Frequency([u8; 10]);
impl Frequency {
    const BLANK: [u8; 10] = [0u8; 10];
    fn clear(&mut self) {
        self.0.copy_from_slice(&Self::BLANK[..]);
    }
    fn new() -> Self {
        Frequency(Frequency::BLANK.clone())
    }
}

struct WildcardExpansion([u32; 10]);
impl WildcardExpansion {
    const BLANK: [u32; 10] = [0u32; 10];
    fn clear(&mut self) {
        self.0.copy_from_slice(&Self::BLANK[..]);
    }
    fn new() -> Self {
        WildcardExpansion(WildcardExpansion::BLANK.clone())
    }
}

fn smallest_prime_with_repetition_of_family(replacement: u8, family_length: u8) -> u32 {
    assert!(family_length > 4);
    let mut sieve = Sieve::new(10_000);
    let mut p = sieve.next_prime();
    while p < 10 {
        p = sieve.next_prime();
    }

    let mut frequency = Frequency::new();
    let mut expansion = WildcardExpansion::new();
    'explorarion: loop {
        appearance_frequency_excluding_tail(p, &mut frequency);
        for (i, _) in frequency
            .0
            .iter()
            .enumerate()
            .filter(|(_, &f)| f == replacement)
        {
            expand_wildcard(p, i as u8, &mut expansion);
            let mut family = expansion.0[1..]
                .iter()
                .map(|&n| n)
                .filter(|&n| sieve.is_prime(n))
                .collect::<Vec<u32>>();
            if sieve.is_prime(expansion.0[0]) && digit_len_match(expansion.0[0], p) {
                family.insert(0, expansion.0[0]);
            }
            if family.len() as u8 == family_length {
                println!("{:?}", &family);
                break 'explorarion family[0];
            }
        }
        p = sieve.next_prime();
    }
}

fn main() {
    {
        let p = smallest_prime_with_repetition_of_family(1, 6);
        assert_eq!(p, 13);
    }
    {
        let p = smallest_prime_with_repetition_of_family(2, 7);
        assert_eq!(p, 56003);
    }
    {
        let p = smallest_prime_with_repetition_of_family(3, 8);
        assert_eq!(p, 121313);
    }
    {
        // timeout with playground
        // https://www.hackerrank.com/contests/projecteuler/challenges/euler051/forum/comments/310849
        // let p = smallest_prime_with_repetition_of_family(4, 6);
        // assert_eq!(p, 2422027);
    }
    {
        // timeout with playground
        // https://www.hackerrank.com/contests/projecteuler/challenges/euler051/forum/comments/592444
        // let p = smallest_prime_with_repetition_of_family(4, 7);
        // assert_eq!(p, 80047003);
    }
    {
        // timeout with playground
        // https://projecteuler.net/action=quote;post_id=382609
        // let p = smallest_prime_with_repetition_of_family(3, 9);
        // assert_eq!(p, 38000201);
    }
}
Problem 52 "Permuted multiples"

It can be seen that the number, 125874, and its double, 251748, contain exactly the same digits, but in a different order.

Find the smallest positive integer, x, such that 2x, 3x, 4x, 5x, and 6x, contain the same digits.

問 52 「置換倍数」

125874を2倍すると251748となる. これは元の数125874と順番は違うが同じ数を含む.

2x, 3x, 4x, 5x, 6x が x と同じ数を含むような最小の正整数 x を求めよ.

const BLANK: [u8; 10] = [0u8; 10];

fn histogram(mut n: u32, digits: &mut [u8; 10]) {
    digits.copy_from_slice(&BLANK);
    while n > 0 {
        let d = (n % 10) as usize;
        digits[d] += 1;
        n /= 10;
    }
}

fn explorarion(place: u32, digit_matrix: &mut [[u8; 10]; 6]) -> Option<u32> {
    'next_x: for x in place..place * 10 / 6 {
        histogram(x, &mut digit_matrix[0]);
        for a in 2usize..=6 {
            histogram(a as u32 * x, &mut digit_matrix[a - 1]);
            if digit_matrix[0] != digit_matrix[a - 1] {
                continue 'next_x;
            }
        }
        return Some(x);
    }
    None
}

fn main() {
    let mut digit_matrix = [[0u8; 10]; 6];
    let mut place = 100u32;
    let n = loop {
        match explorarion(place, &mut digit_matrix) {
            Some(n) => break n,
            None => place *= 10,
        }
    };
    println!("{}", n);
    assert_eq!(n, 142857);
}
Problem 53 "Combinatoric selections"

There are exactly ten ways of selecting three from five, 12345:

123, 124, 125, 134, 135, 145, 234, 235, 245, and 345

In combinatorics, we use the notation, \( \binom{5}{3} = 10 \).

In general, \( \binom{n}{r} = \dfrac{n!}{r!(n-r)!} \), where \(r \le n \), \( n! = n \times (n-1) \times ... \times 3 \times 2 \times 1 \), and \(0! = 1\).

It is not until \(n = 23\), that a value exceeds one-million: \( \binom{23}{10} = 1144066 \).

How many, not necessarily distinct, values of \( \binom{n}{r} \) for\( 1 \le n \le 100 \), are greater than one-million?

問 53 「組み合わせ選択」

12345から3つ選ぶ選び方は10通りである.

123, 124, 125, 134, 135, 145, 234, 235, 245, 345.

組み合わせでは, 以下の記法を用いてこのことを表す: \( \binom{5}{3} = 10 \).

一般に, \(r \le n \) について \( \binom{n}{r} = \dfrac{n!}{r!(n-r)!} \) である.

ここで, \( n! = n \times (n-1) \times ... \times 3 \times 2 \times 1 \) と階乗を定義する.

n = 23 になるまで, これらの値が100万を超えることはない: \( \binom{23}{10} = 1144066 \).

1 ≤ n ≤ 100 について, 100万を超える \( \binom{n}{r} \) は何通りあるか?

const ONE_MILLION: u32 = 1_000_000;

fn main() {
    let mut count = 0u32;
    let mut prev = [0u32; 101];
    let mut line = [0u32; 101];
    prev[0] = 1;
    for _ in 0..100 {
        line[0] = 1;
        for (i, &v) in prev.iter().enumerate() {
            if v == 0 {
                break;
            }
            let binom = v + prev[i + 1];
            line[i + 1] = if binom > ONE_MILLION {
                count += 1;
                ONE_MILLION
            } else {
                binom
            }
        }
        prev.copy_from_slice(&line);
    }

    println!("{}", count);
    assert_eq!(count, 4075);
}
Problem 54 "Poker hands"

In the card game poker, a hand consists of five cards and are ranked, from lowest to highest, in the following way:

  • High Card: Highest value card.
  • One Pair: Two cards of the same value.
  • Two Pairs: Two different pairs.
  • Three of a Kind: Three cards of the same value.
  • Straight: All cards are consecutive values.
  • Flush: All cards of the same suit.
  • Full House: Three of a kind and a pair.
  • Four of a Kind: Four cards of the same value.
  • Straight Flush: All cards are consecutive values of same suit.
  • Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.

The cards are valued in the order:
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.

If two players have the same ranked hands then the rank made up of the highest value wins; for example, a pair of eights beats a pair of fives (see example 1 below). But if two ranks tie, for example, both players have a pair of queens, then highest cards in each hand are compared (see example 4 below); if the highest cards tie then the next highest cards are compared, and so on.

Consider the following five hands dealt to two players:

Hand Player 1 Player 2 Winner
1 5H 5C 6S 7S KD
Pair of Fives
2C 3S 8S 8D TD
Pair of Eights
Player 2
2 5D 8C 9S JS AC
Highest card Ace
2C 5C 7D 8S QH
Highest card Queen
Player 1
3 2D 9C AS AH AC
Three Aces
3D 6D 7D TD QD
Flush with Diamonds
Player 2
4 4D 6S 9H QH QC
Pair of Queens
Highest card Nine
3D 6D 7H QD QS
Pair of Queens
Highest card Seven
Player 1
5 2H 2D 4C 4D 4S
Full House
With Three Fours
3C 3D 3S 9S 9D
Full House
with Three Threes
Player 1

The file, poker.txt, contains one-thousand random hands dealt to two players. Each line of the file contains ten cards (separated by a single space): the first five are Player 1's cards and the last five are Player 2's cards. You can assume that all hands are valid (no invalid characters or repeated cards), each player's hand is in no specific order, and in each hand there is a clear winner.

How many hands does Player 1 win?

問 54 「ポーカーハンド」

カードゲームのポーカーでは, 手札は5枚のカードからなりランク付けされている. 役を低い方から高い方へ順に並べると以下である.

  • 役無し(ハイカード): 一番値が大きいカード
  • ワン・ペア: 同じ値のカードが2枚
  • ツー・ペア: 2つの異なる値のペア
  • スリーカード: 同じ値のカードが3枚
  • ストレート: 5枚の連続する値のカード
  • フラッシュ: 全てのカードが同じスート (注: スートとはダイヤ・ハート・クラブ/スペードというカードの絵柄のこと)
  • フルハウス: スリーカードとペア
  • フォーカード: 同じ値のカードが4枚
  • ストレートフラッシュ: ストレートかつフラッシュ
  • ロイヤルフラッシュ: 同じスートの10, J, Q, K, A

ここでカードの値は小さい方から2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, Aである. (訳注:データ中で10は'T'と表される)

もし2人のプレイヤーが同じ役の場合には, 役を構成する中で値が最も大きいカードによってランクが決まる:

例えば, 8のペアは5のペアより強い (下の例1を見よ).

それでも同じランクの場合には (例えば, 両者ともQのペアの場合), 一番値が大きいカードによってランクが決まる (下の例4を見よ).

一番値が大きいカードが同じ場合には, 次に値が大きいカードが比べれられ, 以下同様にランクを決定する.

poker.txtには1000個のランダムな手札の組が含まれている.

各行は10枚のカードからなる (スペースで区切られている): 最初の5枚がプレイヤー1の手札であり, 残りの5枚がプレイヤー2の手札である.

以下のことを仮定してよい

  • 全ての手札は正しい (使われない文字が出現しない. 同じカードは繰り返されない)
  • 各プレイヤーの手札は特に決まった順に並んでいるわけではない
  • 各勝負で勝敗は必ず決まる

1000回中プレイヤー1が勝つのは何回か?

(訳注 : この問題に置いてA 2 3 4 5というストレートは考えなくてもよい)

use std::slice::Iter;

#[derive(Clone, PartialEq)]
enum Symbol {
    Spade,
    Diamond,
    Club,
    Heart,
}

impl Symbol {
    fn iterator() -> Iter<'static, Symbol> {
        use self::Symbol::*;
        static SYMBOLS: [Symbol; 4] = [Spade, Diamond, Club, Heart];
        SYMBOLS.iter()
    }
}

#[derive(Clone)]
struct Card {
    num: u8,
    symbol: Symbol,
}

impl Default for Card {
    fn default() -> Self {
        Card {
            num: 1,
            symbol: Symbol::Heart,
        }
    }
}

struct Game {
    hands: [[Card; 5]; 2],
    histograms: [[u8; 13]; 2],
}

impl Game {
    const BLANK: [u8; 13] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    fn new() -> Self {
        let c = Card {
            ..Default::default()
        };
        Game {
            hands: [
                [c.clone(), c.clone(), c.clone(), c.clone(), c.clone()],
                [c.clone(), c.clone(), c.clone(), c.clone(), c.clone()],
            ],
            histograms: [Self::BLANK.clone(); 2],
        }
    }
    fn load(&mut self, text: &str) {
        self.histograms[0].copy_from_slice(&Self::BLANK);
        self.histograms[1].copy_from_slice(&Self::BLANK);
        for (i, t) in text.split_ascii_whitespace().enumerate() {
            let card = &mut self.hands[i / 5][i % 5];
            card.num = match t.chars().nth(0).unwrap() {
                'A' => 1,
                '2' => 2,
                '3' => 3,
                '4' => 4,
                '5' => 5,
                '6' => 6,
                '7' => 7,
                '8' => 8,
                '9' => 9,
                'T' => 10,
                'J' => 11,
                'Q' => 12,
                'K' => 13,
                _ => unreachable!(),
            };
            self.histograms[i / 5][card.num as usize - 1] += 1;
            card.symbol = match t.chars().nth(1).unwrap() {
                'S' => Symbol::Spade,
                'D' => Symbol::Diamond,
                'C' => Symbol::Club,
                'H' => Symbol::Heart,
                _ => unreachable!(),
            };
        }
    }
    fn has_left_higher_card(&self) -> bool {
        match (self.histograms[0][0] > 0, self.histograms[1][0] > 0) {
            (true, false) => return true,
            (false, true) => return false,
            _ => (),
        }
        let l = self.hands[0].iter().map(|c| c.num).max().unwrap();
        let r = self.hands[1].iter().map(|c| c.num).max().unwrap();
        if l != r {
            return l > r;
        } else {
            unimplemented!("not only max, need to do further comparison")
        }
    }
    fn is_left_winner(&self) -> bool {
        match (
            has_royal_flush(&self.hands[0]),
            has_royal_flush(&self.hands[1]),
        ) {
            (true, false) => return true,
            (false, true) => return false,
            (false, false) => (),
            (true, true) => panic!(),
        }

        match (
            has_straight_flush(&self.hands[0]),
            has_straight_flush(&self.hands[1]),
        ) {
            (Some(_), None) => return true,
            (None, Some(_)) => return false,
            (None, None) => (),
            (Some(l), Some(r)) => {
                if l != r {
                    return l > r;
                } else {
                    panic!()
                }
            }
        }

        match (
            has_four_of_a_kind(&self.histograms[0]),
            has_four_of_a_kind(&self.histograms[1]),
        ) {
            (Some(_), None) => return true,
            (None, Some(_)) => return false,
            (None, None) => (),
            (Some((l4, l1)), Some((r4, r1))) => {
                if l4 != r4 {
                    return l4 > r4;
                } else if l1 != r1 {
                    return l1 > r1;
                } else {
                    panic!()
                }
            }
        }

        match (
            has_full_house(&self.histograms[0]),
            has_full_house(&self.histograms[1]),
        ) {
            (Some(_), None) => return true,
            (None, Some(_)) => return false,
            (None, None) => (),
            (Some((l3, l2)), Some((r3, r2))) => {
                if l3 != r3 {
                    return l3 > r3;
                } else if l2 != r2 {
                    return l2 > r2;
                } else {
                    panic!()
                }
            }
        }

        match (has_flush(&self.hands[0]), has_flush(&self.hands[1])) {
            (Some(_), None) => return true,
            (None, Some(_)) => return false,
            (None, None) => (),
            (Some(l), Some(r)) => {
                if l != r {
                    return l > r;
                } else {
                    panic!()
                }
            }
        }

        match (has_straight(&self.hands[0]), has_straight(&self.hands[1])) {
            (Some(_), None) => return true,
            (None, Some(_)) => return false,
            (None, None) => (),
            (Some(l), Some(r)) => {
                if l != r {
                    return l > r;
                } else {
                    panic!()
                }
            }
        }

        match (
            has_three_of_a_kind(&self.histograms[0]),
            has_three_of_a_kind(&self.histograms[1]),
        ) {
            (Some(_), None) => return true,
            (None, Some(_)) => return false,
            (None, None) => (),
            (Some((l3, lo)), Some((r3, ro))) => {
                if l3 != r3 {
                    return l3 > r3;
                } else if lo != ro {
                    return lo > ro;
                } else {
                    unimplemented!("need to compare the weakest card")
                }
            }
        }

        match (
            has_two_pairs(&self.histograms[0]),
            has_two_pairs(&self.histograms[1]),
        ) {
            (Some(_), None) => return true,
            (None, Some(_)) => return false,
            (None, None) => (),
            (Some((lg, ll, lo)), Some((rg, rl, ro))) => {
                if lg != rg {
                    return lg > rg;
                } else if ll != rl {
                    return ll > rl;
                } else if lo != ro {
                    return lo > ro;
                } else {
                    panic!()
                }
            }
        }

        match (
            has_one_pair(&self.histograms[0]),
            has_one_pair(&self.histograms[1]),
        ) {
            (Some(_), None) => return true,
            (None, Some(_)) => return false,
            (None, None) => (),
            (Some((l, lo)), Some((r, ro))) => {
                if l != r {
                    return l > r;
                } else if lo != ro {
                    return lo > ro;
                } else {
                    unimplemented!("need to compare the two weakest cards")
                }
            }
        }

        self.has_left_higher_card()
    }
}

fn has_royal_flush(hand: &[Card; 5]) -> bool {
    if !Symbol::iterator().any(|s| hand.iter().all(|c| c.symbol == *s)) {
        return false;
    }
    let mut bits = 0u32;
    hand.iter().for_each(|c| bits |= 1u32 << c.num);
    bits == 0b11110000000010
}

fn has_straight_flush(hand: &[Card; 5]) -> Option<u32> {
    if !Symbol::iterator().any(|s| hand.iter().all(|c| c.symbol == *s)) {
        return None;
    }
    let mut bits = 0u32;
    hand.iter().for_each(|c| bits |= 1u32 << c.num);
    let mut mask = 0b11111000000000u32;
    while mask & 0b01 == 0 {
        if bits == mask {
            return Some(bits);
        }
        mask >>= 1;
    }
    None
}

/// has_four_of_a_kind returns Option<(four, one)>
fn has_four_of_a_kind(histogram: &[u8; 13]) -> Option<(u8, u8)> {
    let (mut four, mut one) = (None, None);
    for (i, &v) in histogram.iter().enumerate() {
        match v {
            4 => four = Some(i),
            1 => one = Some(i),
            _ => (),
        }
    }
    match (four, one) {
        (Some(f), Some(o)) => Some((
            if f == 0 { u8::MAX } else { f as u8 },
            if o == 0 { u8::MAX } else { o as u8 },
        )),
        _ => None,
    }
}

/// has_full_house returns Option<(triple, pair)>
fn has_full_house(histogram: &[u8; 13]) -> Option<(u8, u8)> {
    let (mut triple, mut pair) = (None, None);
    for (i, &v) in histogram.iter().enumerate() {
        match v {
            3 => triple = Some(i),
            2 => pair = Some(i),
            _ => (),
        }
    }
    match (triple, pair) {
        (Some(t), Some(p)) => Some((
            if t == 0 { u8::MAX } else { t as u8 },
            if p == 0 { u8::MAX } else { p as u8 },
        )),
        _ => None,
    }
}

fn has_flush(hand: &[Card; 5]) -> Option<u8> {
    if !Symbol::iterator().any(|s| hand.iter().all(|c| c.symbol == *s)) {
        return None;
    }
    Some(hand.iter().map(|c| c.num).max().unwrap())
}

fn has_straight(hand: &[Card; 5]) -> Option<u32> {
    let mut bits = 0u32;
    hand.iter().for_each(|c| bits |= 1u32 << c.num);
    if bits == 0b11110000000010 {
        return Some(u32::MAX);
    }
    let mut mask = 0b11111000000000u32;
    while mask & 0b01 == 0 {
        if bits == mask {
            return Some(mask);
        }
        mask >>= 1;
    }
    None
}

/// has_three_of_a_kind returns Option<(three, max(other))>
fn has_three_of_a_kind(histogram: &[u8; 13]) -> Option<(u8, u8)> {
    let (mut triple, mut other) = (None, None);
    for (i, &v) in histogram.iter().enumerate() {
        match v {
            3 => triple = Some(i),
            n if n > 0 && i == 0 => other = Some(0),
            n if n > 0 => other = std::cmp::max(other, Some(i)),
            _ => (),
        }
    }
    match (triple, other) {
        (Some(t), Some(o)) => Some((
            if t == 0 { u8::MAX } else { t as u8 },
            if o == 0 { u8::MAX } else { o as u8 },
        )),
        _ => None,
    }
}

/// has_two_pairs returns Option<(higher, lower, other)>
fn has_two_pairs(histogram: &[u8; 13]) -> Option<(u8, u8, u8)> {
    let mut iter = histogram
        .iter()
        .enumerate()
        .filter(|(_, &c)| c == 2)
        .map(|(i, _)| if i == 0 { u8::MAX } else { i as u8 });
    let a = iter.next();
    let b = iter.next();
    match (a, b) {
        (Some(i), Some(j)) => {
            let c = histogram
                .iter()
                .enumerate()
                .filter(|(_, &c)| c == 1)
                .map(|(i, _)| if i == 0 { u8::MAX } else { i as u8 })
                .next()
                .unwrap();
            Some((std::cmp::max(i, j), std::cmp::min(i, j), c))
        }
        _ => None,
    }
}

/// has_one_pair returns Option<(pair, max(other))>
fn has_one_pair(histogram: &[u8; 13]) -> Option<(u8, u8)> {
    if histogram.iter().filter(|&c| *c == 2).count() != 1 {
        return None;
    }
    let (mut pair, mut other) = (None, None);
    for (i, &v) in histogram.iter().enumerate() {
        match v {
            2 => pair = Some(i),
            n if n > 0 && i == 0 => other = Some(0),
            n if n > 0 => other = std::cmp::max(other, Some(i)),
            _ => (),
        }
    }
    match (pair, other) {
        (Some(p), Some(o)) => Some((
            if p == 0 { u8::MAX } else { p as u8 },
            if o == 0 { u8::MAX } else { o as u8 },
        )),
        _ => None,
    }
}

fn main() {
    let mut game = Game::new();
    let mut count = 0u32;
    for source in GAMES.iter() {
        game.load(source);
        if game.is_left_winner() {
            count += 1;
        }
    }

    println!("{}", count);
    assert_eq!(count, 376);
}

const GAMES: [&str; 1000] = [
    "8C TS KC 9H 4S 7D 2S 5D 3S AC",
    "5C AD 5D AC 9C 7C 5H 8D TD KS",
    "3H 7H 6S KC JS QH TD JC 2D 8S",
    "TH 8H 5C QS TC 9H 4D JC KS JS",
    "7C 5H KC QH JD AS KH 4C AD 4S",
    "5H KS 9C 7D 9H 8D 3S 5D 5C AH",
    "6H 4H 5C 3H 2H 3S QH 5S 6S AS",
    "TD 8C 4H 7C TC KC 4C 3H 7S KS",
    "7C 9C 6D KD 3H 4C QS QC AC KH",
    "JC 6S 5H 2H 2D KD 9D 7C AS JS",
    "AD QH TH 9D 8H TS 6D 3S AS AC",
    "2H 4S 5C 5S TC KC JD 6C TS 3C",
    "QD AS 6H JS 2C 3D 9H KC 4H 8S",
    "KD 8S 9S 7C 2S 3S 6D 6S 4H KC",
    "3C 8C 2D 7D 4D 9S 4S QH 4H JD",
    "8C KC 7S TC 2D TS 8H QD AC 5C",
    "3D KH QD 6C 6S AD AS 8H 2H QS",
    "6S 8D 4C 8S 6C QH TC 6D 7D 9D",
    "2S 8D 8C 4C TS 9S 9D 9C AC 3D",
    "3C QS 2S 4H JH 3D 2D TD 8S 9H",
    "5H QS 8S 6D 3C 8C JD AS 7H 7D",
    "6H TD 9D AS JH 6C QC 9S KD JC",
    "AH 8S QS 4D TH AC TS 3C 3D 5C",
    "5S 4D JS 3D 8H 6C TS 3S AD 8C",
    "6D 7C 5D 5H 3S 5C JC 2H 5S 3D",
    "5H 6H 2S KS 3D 5D JD 7H JS 8H",
    "KH 4H AS JS QS QC TC 6D 7C KS",
    "3D QS TS 2H JS 4D AS 9S JC KD",
    "QD 5H 4D 5D KH 7H 3D JS KD 4H",
    "2C 9H 6H 5C 9D 6C JC 2D TH 9S",
    "7D 6D AS QD JH 4D JS 7C QS 5C",
    "3H KH QD AD 8C 8H 3S TH 9D 5S",
    "AH 9S 4D 9D 8S 4H JS 3C TC 8D",
    "2C KS 5H QD 3S TS 9H AH AD 8S",
    "5C 7H 5D KD 9H 4D 3D 2D KS AD",
    "KS KC 9S 6D 2C QH 9D 9H TS TC",
    "9C 6H 5D QH 4D AD 6D QC JS KH",
    "9S 3H 9D JD 5C 4D 9H AS TC QH",
    "2C 6D JC 9C 3C AD 9S KH 9D 7D",
    "KC 9C 7C JC JS KD 3H AS 3C 7D",
    "QD KH QS 2C 3S 8S 8H 9H 9C JC",
    "QH 8D 3C KC 4C 4H 6D AD 9H 9D",
    "3S KS QS 7H KH 7D 5H 5D JD AD",
    "2H 2C 6H TH TC 7D 8D 4H 8C AS",
    "4S 2H AC QC 3S 6D TH 4D 4C KH",
    "4D TC KS AS 7C 3C 6D 2D 9H 6C",
    "8C TD 5D QS 2C 7H 4C 9C 3H 9H",
    "5H JH TS 7S TD 6H AD QD 8H 8S",
    "5S AD 9C 8C 7C 8D 5H 9D 8S 2S",
    "4H KH KS 9S 2S KC 5S AD 4S 7D",
    "QS 9C QD 6H JS 5D AC 8D 2S AS",
    "KH AC JC 3S 9D 9S 3C 9C 5S JS",
    "AD 3C 3D KS 3S 5C 9C 8C TS 4S",
    "JH 8D 5D 6H KD QS QD 3D 6C KC",
    "8S JD 6C 3S 8C TC QC 3C QH JS",
    "KC JC 8H 2S 9H 9C JH 8S 8C 9S",
    "8S 2H QH 4D QC 9D KC AS TH 3C",
    "8S 6H TH 7C 2H 6S 3C 3H AS 7S",
    "QH 5S JS 4H 5H TS 8H AH AC JC",
    "9D 8H 2S 4S TC JC 3C 7H 3H 5C",
    "3D AD 3C 3S 4C QC AS 5D TH 8C",
    "6S 9D 4C JS KH AH TS JD 8H AD",
    "4C 6S 9D 7S AC 4D 3D 3S TC JD",
    "AD 7H 6H 4H JH KC TD TS 7D 6S",
    "8H JH TC 3S 8D 8C 9S 2C 5C 4D",
    "2C 9D KC QH TH QS JC 9C 4H TS",
    "QS 3C QD 8H KH 4H 8D TD 8S AC",
    "7C 3C TH 5S 8H 8C 9C JD TC KD",
    "QC TC JD TS 8C 3H 6H KD 7C TD",
    "JH QS KS 9C 6D 6S AS 9H KH 6H",
    "2H 4D AH 2D JH 6H TD 5D 4H JD",
    "KD 8C 9S JH QD JS 2C QS 5C 7C",
    "4S TC 7H 8D 2S 6H 7S 9C 7C KC",
    "8C 5D 7H 4S TD QC 8S JS 4H KS",
    "AD 8S JH 6D TD KD 7C 6C 2D 7D",
    "JC 6H 6S JS 4H QH 9H AH 4C 3C",
    "6H 5H AS 7C 7S 3D KH KC 5D 5C",
    "JC 3D TD AS 4D 6D 6S QH JD KS",
    "8C 7S 8S QH 2S JD 5C 7H AH QD",
    "8S 3C 6H 6C 2C 8D TD 7D 4C 4D",
    "5D QH KH 7C 2S 7H JS 6D QC QD",
    "AD 6C 6S 7D TH 6H 2H 8H KH 4H",
    "KS JS KD 5D 2D KH 7D 9C 8C 3D",
    "9C 6D QD 3C KS 3S 7S AH JD 2D",
    "AH QH AS JC 8S 8H 4C KC TH 7D",
    "JC 5H TD 7C 5D KD 4C AD 8H JS",
    "KC 2H AC AH 7D JH KH 5D 7S 6D",
    "9S 5S 9C 6H 8S TD JD 9H 6C AC",
    "7D 8S 6D TS KD 7H AC 5S 7C 5D",
    "AH QC JC 4C TC 8C 2H TS 2C 7D",
    "KD KC 6S 3D 7D 2S 8S 3H 5S 5C",
    "8S 5D 8H 4C 6H KC 3H 7C 5S KD",
    "JH 8C 3D 3C 6C KC TD 7H 7C 4C",
    "JC KC 6H TS QS TD KS 8H 8C 9S",
    "6C 5S 9C QH 7D AH KS KC 9S 2C",
    "4D 4S 8H TD 9C 3S 7D 9D AS TH",
    "6S 7D 3C 6H 5D KD 2C 5C 9D 9C",
    "2H KC 3D AD 3H QD QS 8D JC 4S",
    "8C 3H 9C 7C AD 5D JC 9D JS AS",
    "5D 9H 5C 7H 6S 6C QC JC QD 9S",
    "JC QS JH 2C 6S 9C QC 3D 4S TC",
    "4H 5S 8D 3D 4D 2S KC 2H JS 2C",
    "TD 3S TH KD 4D 7H JH JS KS AC",
    "7S 8C 9S 2D 8S 7D 5C AD 9D AS",
    "8C 7H 2S 6C TH 3H 4C 3S 8H AC",
    "KD 5H JC 8H JD 2D 4H TD JH 5C",
    "3D AS QH KS 7H JD 8S 5S 6D 5H",
    "9S 6S TC QS JC 5C 5D 9C TH 8C",
    "5H 3S JH 9H 2S 2C 6S 7S AS KS",
    "8C QD JC QS TC QC 4H AC KH 6C",
    "TC 5H 7D JH 4H 2H 8D JC KS 4D",
    "5S 9C KH KD 9H 5C TS 3D 7D 2D",
    "5H AS TC 4D 8C 2C TS 9D 3H 8D",
    "6H 8D 2D 9H JD 6C 4S 5H 5S 6D",
    "AD 9C JC 7D 6H 9S 6D JS 9H 3C",
    "AD JH TC QS 4C 5D 9S 7C 9C AH",
    "KD 6H 2H TH 8S QD KS 9D 9H AS",
    "4H 8H 8D 5H 6C AH 5S AS AD 8S",
    "QS 5D 4S 2H TD KS 5H AC 3H JC",
    "9C 7D QD KD AC 6D 5H QH 6H 5S",
    "KC AH QH 2H 7D QS 3H KS 7S JD",
    "6C 8S 3H 6D KS QD 5D 5C 8H TC",
    "9H 4D 4S 6S 9D KH QC 4H 6C JD",
    "TD 2D QH 4S 6H JH KD 3C QD 8C",
    "4S 6H 7C QD 9D AS AH 6S AD 3C",
    "2C KC TH 6H 8D AH 5C 6D 8S 5D",
    "TD TS 7C AD JC QD 9H 3C KC 7H",
    "5D 4D 5S 8H 4H 7D 3H JD KD 2D",
    "JH TD 6H QS 4S KD 5C 8S 7D 8H",
    "AC 3D AS 8C TD 7H KH 5D 6C JD",
    "9D KS 7C 6D QH TC JD KD AS KC",
    "JH 8S 5S 7S 7D AS 2D 3D AD 2H",
    "2H 5D AS 3C QD KC 6H 9H 9S 2C",
    "9D 5D TH 4C JH 3H 8D TC 8H 9H",
    "6H KD 2C TD 2H 6C 9D 2D JS 8C",
    "KD 7S 3C 7C AS QH TS AD 8C 2S",
    "QS 8H 6C JS 4C 9S QC AD TD TS",
    "2H 7C TS TC 8C 3C 9H 2D 6D JC",
    "TC 2H 8D JH KS 6D 3H TD TH 8H",
    "9D TD 9H QC 5D 6C 8H 8C KC TS",
    "2H 8C 3D AH 4D TH TC 7D 8H KC",
    "TS 5C 2D 8C 6S KH AH 5H 6H KC",
    "5S 5D AH TC 4C JD 8D 6H 8C 6C",
    "KC QD 3D 8H 2D JC 9H 4H AD 2S",
    "TD 6S 7D JS KD 4H QS 2S 3S 8C",
    "4C 9H JH TS 3S 4H QC 5S 9S 9C",
    "2C KD 9H JS 9S 3H JC TS 5D AC",
    "AS 2H 5D AD 5H JC 7S TD JS 4C",
    "2D 4S 8H 3D 7D 2C AD KD 9C TS",
    "7H QD JH 5H JS AC 3D TH 4C 8H",
    "6D KH KC QD 5C AD 7C 2D 4H AC",
    "3D 9D TC 8S QD 2C JC 4H JD AH",
    "6C TD 5S TC 8S AH 2C 5D AS AC",
    "TH 7S 3D AS 6C 4C 7H 7D 4H AH",
    "5C 2H KS 6H 7S 4H 5H 3D 3C 7H",
    "3C 9S AC 7S QH 2H 3D 6S 3S 3H",
    "2D 3H AS 2C 6H TC JS 6S 9C 6C",
    "QH KD QD 6D AC 6H KH 2C TS 8C",
    "8H 7D 3S 9H 5D 3H 4S QC 9S 5H",
    "2D 9D 7H 6H 3C 8S 5H 4D 3S 4S",
    "KD 9S 4S TC 7S QC 3S 8S 2H 7H",
    "TC 3D 8C 3H 6C 2H 6H KS KD 4D",
    "KC 3D 9S 3H JS 4S 8H 2D 6C 8S",
    "6H QS 6C TC QD 9H 7D 7C 5H 4D",
    "TD 9D 8D 6S 6C TC 5D TS JS 8H",
    "4H KC JD 9H TC 2C 6S 5H 8H AS",
    "JS 9C 5C 6S 9D JD 8H KC 4C 6D",
    "4D 8D 8S 6C 7C 6H 7H 8H 5C KC",
    "TC 3D JC 6D KS 9S 6H 7S 9C 2C",
    "6C 3S KD 5H TS 7D 9H 9S 6H KH",
    "3D QD 4C 6H TS AC 3S 5C 2H KD",
    "4C AS JS 9S 7C TS 7H 9H JC KS",
    "4H 8C JD 3H 6H AD 9S 4S 5S KS",
    "4C 2C 7D 3D AS 9C 2S QS KC 6C",
    "8S 5H 3D 2S AC 9D 6S 3S 4D TD",
    "QD TH 7S TS 3D AC 7H 6C 5D QC",
    "TC QD AD 9C QS 5C 8D KD 3D 3C",
    "9D 8H AS 3S 7C 8S JD 2D 8D KC",
    "4C TH AC QH JS 8D 7D 7S 9C KH",
    "9D 8D 4C JH 2C 2S QD KD TS 4H",
    "4D 6D 5D 2D JH 3S 8S 3H TC KH",
    "AD 4D 2C QS 8C KD JH JD AH 5C",
    "5C 6C 5H 2H JH 4H KS 7C TC 3H",
    "3C 4C QC 5D JH 9C QD KH 8D TC",
    "3H 9C JS 7H QH AS 7C 9H 5H JC",
    "2D 5S QD 4S 3C KC 6S 6C 5C 4C",
    "5D KH 2D TS 8S 9C AS 9S 7C 4C",
    "7C AH 8C 8D 5S KD QH QS JH 2C",
    "8C 9D AH 2H AC QC 5S 8H 7H 2C",
    "QD 9H 5S QS QC 9C 5H JC TH 4H",
    "6C 6S 3H 5H 3S 6H KS 8D AC 7S",
    "AC QH 7H 8C 4S KC 6C 3D 3S TC",
    "9D 3D JS TH AC 5H 3H 8S 3S TC",
    "QD KH JS KS 9S QC 8D AH 3C AC",
    "5H 6C KH 3S 9S JH 2D QD AS 8C",
    "6C 4D 7S 7H 5S JC 6S 9H 4H JH",
    "AH 5S 6H 9S AD 3S TH 2H 9D 8C",
    "4C 8D 9H 7C QC AD 4S 9C KC 5S",
    "9D 6H 4D TC 4C JH 2S 5D 3S AS",
    "2H 6C 7C KH 5C AD QS TH JD 8S",
    "3S 4S 7S AH AS KC JS 2S AD TH",
    "JS KC 2S 7D 8C 5C 9C TS 5H 9D",
    "7S 9S 4D TD JH JS KH 6H 5D 2C",
    "JD JS JC TH 2D 3D QD 8C AC 5H",
    "7S KH 5S 9D 5D TD 4S 6H 3C 2D",
    "4S 5D AC 8D 4D 7C AD AS AH 9C",
    "6S TH TS KS 2C QC AH AS 3C 4S",
    "2H 8C 3S JC 5C 7C 3H 3C KH JH",
    "7S 3H JC 5S 6H 4C 2S 4D KC 7H",
    "4D 7C 4H 9S 8S 6S AD TC 6C JC",
    "KH QS 3S TC 4C 8H 8S AC 3C TS",
    "QD QS TH 3C TS 7H 7D AH TD JC",
    "TD JD QC 4D 9S 7S TS AD 7D AC",
    "AH 7H 4S 6D 7C 2H 9D KS JC TD",
    "7C AH JD 4H 6D QS TS 2H 2C 5C",
    "TC KC 8C 9S 4C JS 3C JC 6S AH",
    "AS 7D QC 3D 5S JC JD 9D TD KH",
    "TH 3C 2S 6H AH AC 5H 5C 7S 8H",
    "QC 2D AC QD 2S 3S JD QS 6S 8H",
    "KC 4H 3C 9D JS 6H 3S 8S AS 8C",
    "7H KC 7D JD 2H JC QH 5S 3H QS",
    "9H TD 3S 8H 7S AC 5C 6C AH 7C",
    "8D 9H AH JD TD QS 7D 3S 9C 8S",
    "AH QH 3C JD KC 4S 5S 5D TD KS",
    "9H 7H 6S JH TH 4C 7C AD 5C 2D",
    "7C KD 5S TC 9D 6S 6C 5D 2S TH",
    "KC 9H 8D 5H 7H 4H QC 3D 7C AS",
    "6S 8S QC TD 4S 5C TH QS QD 2S",
    "8S 5H TH QC 9H 6S KC 7D 7C 5C",
    "7H KD AH 4D KH 5C 4S 2D KC QH",
    "6S 2C TD JC AS 4D 6C 8C 4H 5S",
    "JC TC JD 5S 6S 8D AS 9D AD 3S",
    "6D 6H 5D 5S TC 3D 7D QS 9D QD",
    "4S 6C 8S 3S 7S AD KS 2D 7D 7C",
    "KC QH JC AC QD 5D 8D QS 7H 7D",
    "JS AH 8S 5H 3D TD 3H 4S 6C JH",
    "4S QS 7D AS 9H JS KS 6D TC 5C",
    "2D 5C 6H TC 4D QH 3D 9H 8S 6C",
    "6D 7H TC TH 5S JD 5C 9C KS KD",
    "8D TD QH 6S 4S 6C 8S KC 5C TC",
    "5S 3D KS AC 4S 7D QD 4C TH 2S",
    "TS 8H 9S 6S 7S QH 3C AH 7H 8C",
    "4C 8C TS JS QC 3D 7D 5D 7S JH",
    "8S 7S 9D QC AC 7C 6D 2H JH KC",
    "JS KD 3C 6S 4S 7C AH QC KS 5H",
    "KS 6S 4H JD QS TC 8H KC 6H AS",
    "KH 7C TC 6S TD JC 5C 7D AH 3S",
    "3H 4C 4H TC TH 6S 7H 6D 9C QH",
    "7D 5H 4S 8C JS 4D 3D 8S QH KC",
    "3H 6S AD 7H 3S QC 8S 4S 7S JS",
    "3S JD KH TH 6H QS 9C 6C 2D QD",
    "4S QH 4D 5H KC 7D 6D 8D TH 5S",
    "TD AD 6S 7H KD KH 9H 5S KC JC",
    "3H QC AS TS 4S QD KS 9C 7S KC",
    "TS 6S QC 6C TH TC 9D 5C 5D KD",
    "JS 3S 4H KD 4C QD 6D 9S JC 9D",
    "8S JS 6D 4H JH 6H 6S 6C KS KH",
    "AC 7D 5D TC 9S KH 6S QD 6H AS",
    "AS 7H 6D QH 8D TH 2S KH 5C 5H",
    "4C 7C 3D QC TC 4S KH 8C 2D JS",
    "6H 5D 7S 5H 9C 9H JH 8S TH 7H",
    "AS JS 2S QD KH 8H 4S AC 8D 8S",
    "3H 4C TD KD 8C JC 5C QS 2D JD",
    "TS 7D 5D 6C 2C QS 2H 3C AH KS",
    "4S 7C 9C 7D JH 6C 5C 8H 9D QD",
    "2S TD 7S 6D 9C 9S QS KH QH 5C",
    "JC 6S 9C QH JH 8D 7S JS KH 2H",
    "8D 5H TH KC 4D 4S 3S 6S 3D QS",
    "2D JD 4C TD 7C 6D TH 7S JC AH",
    "QS 7S 4C TH 9D TS AD 4D 3H 6H",
    "2D 3H 7D JD 3D AS 2S 9C QC 8S",
    "4H 9H 9C 2C 7S JH KD 5C 5D 6H",
    "TC 9H 8H JC 3C 9S 8D KS AD KC",
    "TS 5H JD QS QH QC 8D 5D KH AH",
    "5D AS 8S 6S 4C AH QC QD TH 7H",
    "3H 4H 7D 6S 4S 9H AS 8H JS 9D",
    "JD 8C 2C 9D 7D 5H 5S 9S JC KD",
    "KD 9C 4S QD AH 7C AD 9D AC TD",
    "6S 4H 4S 9C 8D KS TC 9D JH 7C",
    "5S JC 5H 4S QH AC 2C JS 2S 9S",
    "8C 5H AS QD AD 5C 7D 8S QC TD",
    "JC 4C 8D 5C KH QS 4D 6H 2H 2C",
    "TH 4S 2D KC 3H QD AC 7H AD 9D",
    "KH QD AS 8H TH KC 8D 7S QH 8C",
    "JC 6C 7D 8C KH AD QS 2H 6S 2D",
    "JC KH 2D 7D JS QC 5H 4C 5D AD",
    "TS 3S AD 4S TD 2D TH 6S 9H JH",
    "9H 2D QS 2C 4S 3D KH AS AC 9D",
    "KH 6S 8H 4S KD 7D 9D TS QD QC",
    "JH 5H AH KS AS AD JC QC 5S KH",
    "5D 7D 6D KS KD 3D 7C 4D JD 3S",
    "AC JS 8D 5H 9C 3H 4H 4D TS 2C",
    "6H KS KH 9D 7C 2S 6S 8S 2H 3D",
    "6H AC JS 7S 3S TD 8H 3H 4H TH",
    "9H TC QC KC 5C KS 6H 4H AC 8S",
    "TC 7D QH 4S JC TS 6D 6C AC KH",
    "QH 7D 7C JH QS QD TH 3H 5D KS",
    "3D 5S 8D JS 4C 2C KS 7H 9C 4H",
    "5H 8S 4H TD 2C 3S QD QC 3H KC",
    "QC JS KD 9C AD 5S 9D 7D 7H TS",
    "8C JC KH 7C 7S 6C TS 2C QD TH",
    "5S 9D TH 3C 7S QH 8S 9C 2H 5H",
    "5D 9H 6H 2S JS KH 3H 7C 2H 5S",
    "JD 5D 5S 2C TC 2S 6S 6C 3C 8S",
    "4D KH 8H 4H 2D KS 3H 5C 2S 9H",
    "3S 2D TD 7H 8S 6H JD KC 9C 8D",
    "6S QD JH 7C 9H 5H 8S 8H TH TD",
    "QS 7S TD 7D TS JC KD 7C 3C 2C",
    "3C JD 8S 4H 2D 2S TD AS 4D AC",
    "AH KS 6C 4C 4S 7D 8C 9H 6H AS",
    "5S 3C 9S 2C QS KD 4D 4S AC 5D",
    "2D TS 2C JS KH QH 5D 8C AS KC",
    "KD 3H 6C TH 8S 7S KH 6H 9S AC",
    "6H 7S 6C QS AH 2S 2H 4H 5D 5H",
    "5H JC QD 2C 2S JD AS QC 6S 7D",
    "6C TC AS KD 8H 9D 2C 7D JH 9S",
    "2H 4C 6C AH 8S TD 3H TH 7C TS",
    "KD 4S TS 6C QH 8D 9D 9C AH 7D",
    "6D JS 5C QD QC 9C 5D 8C 2H KD",
    "3C QH JH AD 6S AH KC 8S 6D 6H",
    "3D 7C 4C 7S 5S 3S 6S 5H JC 3C",
    "QH 7C 5H 3C 3S 8C TS 4C KD 9C",
    "QD 3S 7S 5H 7H QH JC 7C 8C KD",
    "3C KD KH 2S 4C TS AC 6S 2C 7C",
    "2C KH 3C 4C 6H 4D 5H 5S 7S QD",
    "4D 7C 8S QD TS 9D KS 6H KD 3C",
    "QS 4D TS 7S 4C 3H QD 8D 9S TC",
    "TS QH AC 6S 3C 9H 9D QS 8S 6H",
    "3S 7S 5D 4S JS 2D 6C QH 6S TH",
    "4C 4H AS JS 5D 3D TS 9C AC 8S",
    "6S 9C 7C 3S 5C QS AD AS 6H 3C",
    "9S 8C 7H 3H 6S 7C AS 9H JD KH",
    "3D 3H 7S 4D 6C 7C AC 2H 9C TH",
    "4H 5S 3H AC TC TH 9C 9H 9S 8D",
    "8D 9H 5H 4D 6C 2H QD 6S 5D 3S",
    "4C 5C JD QS 4D 3H TH AC QH 8C",
    "QC 5S 3C 7H AD 4C KS 4H JD 6D",
    "QS AH 3H KS 9H 2S JS JH 5H 2H",
    "2H 5S TH 6S TS 3S KS 3C 5H JS",
    "2D 9S 7H 3D KC JH 6D 7D JS TD",
    "AC JS 8H 2C 8C JH JC 2D TH 7S",
    "5D 9S 8H 2H 3D TC AH JC KD 9C",
    "9D QD JC 2H 6D KH TS 9S QH TH",
    "2C 8D 4S JD 5H 3H TH TC 9C KC",
    "AS 3D 9H 7D 4D TH KH 2H 7S 3H",
    "4H 7S KS 2S JS TS 8S 2H QD 8D",
    "5S 6H JH KS 8H 2S QC AC 6S 3S",
    "JC AS AD QS 8H 6C KH 4C 4D QD",
    "2S 3D TS TD 9S KS 6S QS 5C 8D",
    "3C 6D 4S QC KC JH QD TH KH AD",
    "9H AH 4D KS 2S 8D JH JC 7C QS",
    "2D 6C TH 3C 8H QD QH 2S 3S KS",
    "6H 5D 9S 4C TS TD JS QD 9D JD",
    "5H 8H KH 8S KS 7C TD AD 4S KD",
    "2C 7C JC 5S AS 6C 7D 8S 5H 9C",
    "6S QD 9S TS KH QS 5S QH 3C KC",
    "7D 3H 3C KD 5C AS JH 7H 6H JD",
    "9D 5C 9H KC 8H KS 4S AD 4D 2S",
    "3S JD QD 8D 2S 7C 5S 6S 5H TS",
    "6D 9S KC TD 3S 6H QD JD 5C 8D",
    "5H 9D TS KD 8D 6H TD QC 4C 7D",
    "6D 4S JD 9D AH 9S AS TD 9H QD",
    "2D 5S 2H 9C 6H 9S TD QC 7D TC",
    "3S 2H KS TS 2C 9C 8S JS 9D 7D",
    "3C KC 6D 5D 6C 6H 8S AS 7S QS",
    "JH 9S 2H 8D 4C 8H 9H AD TH KH",
    "QC AS 2S JS 5C 6H KD 3H 7H 2C",
    "QD 8H 2S 8D 3S 6D AH 2C TC 5C",
    "JD JS TS 8S 3H 5D TD KC JC 6H",
    "6S QS TC 3H 5D AH JC 7C 7D 4H",
    "7C 5D 8H 9C 2H 9H JH KH 5S 2C",
    "9C 7H 6S TH 3S QC QD 4C AC JD",
    "2H 5D 9S 7D KC 3S QS 2D AS KH",
    "2S 4S 2H 7D 5C TD TH QH 9S 4D",
    "6D 3S TS 6H 4H KS 9D 8H 5S 2D",
    "9H KS 4H 3S 5C 5D KH 6H 6S JS",
    "KC AS 8C 4C JC KH QC TH QD AH",
    "6S KH 9S 2C 5H TC 3C 7H JC 4D",
    "JD 4S 6S 5S 8D 7H 7S 4D 4C 2H",
    "7H 9H 5D KH 9C 7C TS TC 7S 5H",
    "4C 8D QC TS 4S 9H 3D AD JS 7C",
    "8C QS 5C 5D 3H JS AH KC 4S 9D",
    "TS JD 8S QS TH JH KH 2D QD JS",
    "JD QC 5D 6S 9H 3S 2C 8H 9S TS",
    "2S 4C AD 7H JC 5C 2D 6D 4H 3D",
    "7S JS 2C 4H 8C AD QD 9C 3S TD",
    "JD TS 4C 6H 9H 7D QD 6D 3C AS",
    "AS 7C 4C 6S 5D 5S 5C JS QC 4S",
    "KD 6S 9S 7C 3C 5S 7D JH QD JS",
    "4S 7S JH 2C 8S 5D 7H 3D QH AD",
    "TD 6H 2H 8D 4H 2D 7C AD KH 5D",
    "TS 3S 5H 2C QD AH 2S 5C KH TD",
    "KC 4D 8C 5D AS 6C 2H 2S 9H 7C",
    "KD JS QC TS QS KH JH 2C 5D AD",
    "3S 5H KC 6C 9H 3H 2H AD 7D 7S",
    "7S JS JH KD 8S 7D 2S 9H 7C 2H",
    "9H 2D 8D QC 6S AD AS 8H 5H 6C",
    "2S 7H 6C 6D 7D 8C 5D 9D JC 3C",
    "7C 9C 7H JD 2H KD 3S KH AD 4S",
    "QH AS 9H 4D JD KS KD TS KH 5H",
    "4C 8H 5S 3S 3D 7D TD AD 7S KC",
    "JS 8S 5S JC 8H TH 9C 4D 5D KC",
    "7C 5S 9C QD 2C QH JS 5H 8D KH",
    "TD 2S KS 3D AD KC 7S TC 3C 5D",
    "4C 2S AD QS 6C 9S QD TH QH 5C",
    "8C AD QS 2D 2S KC JD KS 6C JC",
    "8D 4D JS 2H 5D QD 7S 7D QH TS",
    "6S 7H 3S 8C 8S 9D QS 8H 6C 9S",
    "4S TC 2S 5C QD 4D QS 6D TH 6S",
    "3S 5C 9D 6H 8D 4C 7D TC 7C TD",
    "AH 6S AS 7H 5S KD 3H 5H AC 4C",
    "8D 8S AH KS QS 2C AD 6H 7D 5D",
    "6H 9H 9S 2H QS 8S 9C 5D 2D KD",
    "TS QC 5S JH 7D 7S TH 9S 9H AC",
    "7H 3H 6S KC 4D 6D 5C 4S QD TS",
    "TD 2S 7C QD 3H JH 9D 4H 7S 7H",
    "KS 3D 4H 5H TC 2S AS 2D 6D 7D",
    "8H 3C 7H TD 3H AD KC TH 9C KH",
    "TC 4C 2C 9S 9D 9C 5C 2H JD 3C",
    "3H AC TS 5D AD 8D 6H QC 6S 8C",
    "2S TS 3S JD 7H 8S QH 4C 5S 8D",
    "AC 4S 6C 3C KH 3D 7C 2D 8S 2H",
    "4H 6C 8S TH 2H 4S 8H 9S 3H 7S",
    "7C 4C 9C 2C 5C AS 5D KD 4D QH",
    "9H 4H TS AS 7D 8D 5D 9S 8C 2H",
    "QC KD AC AD 2H 7S AS 3S 2D 9S",
    "2H QC 8H TC 6D QD QS 5D KH 3C",
    "TH JD QS 4C 2S 5S AD 7H 3S AS",
    "7H JS 3D 6C 3S 6D AS 9S AC QS",
    "9C TS AS 8C TC 8S 6H 9D 8D 6C",
    "4D JD 9C KC 7C 6D KS 3S 8C AS",
    "3H 6S TC 8D TS 3S KC 9S 7C AS",
    "8C QC 4H 4S 8S 6C 3S TC AH AC",
    "4D 7D 5C AS 2H 6S TS QC AD TC",
    "QD QC 8S 4S TH 3D AH TS JH 4H",
    "5C 2D 9S 2C 3H 3C 9D QD QH 7D",
    "KC 9H 6C KD 7S 3C 4D AS TC 2D",
    "3D JS 4D 9D KS 7D TH QC 3H 3C",
    "8D 5S 2H 9D 3H 8C 4C 4H 3C TH",
    "JC TH 4S 6S JD 2D 4D 6C 3D 4C",
    "TS 3S 2D 4H AC 2C 6S 2H JH 6H",
    "TD 8S AD TC AH AC JH 9S 6S 7S",
    "6C KC 4S JD 8D 9H 5S 7H QH AH",
    "KD 8D TS JH 5C 5H 3H AD AS JS",
    "2D 4H 3D 6C 8C 7S AD 5D 5C 8S",
    "TD 5D 7S 9C 4S 5H 6C 8C 4C 8S",
    "JS QH 9C AS 5C QS JC 3D QC 7C",
    "JC 9C KH JH QS QC 2C TS 3D AD",
    "5D JH AC 5C 9S TS 4C JD 8C KS",
    "KC AS 2D KH 9H 2C 5S 4D 3D 6H",
    "TH AH 2D 8S JC 3D 8C QH 7S 3S",
    "8H QD 4H JC AS KH KS 3C 9S 6D",
    "9S QH 7D 9C 4S AC 7H KH 4D KD",
    "AH AD TH 6D 9C 9S KD KS QH 4H",
    "QD 6H 9C 7C QS 6D 6S 9D 5S JH",
    "AH 8D 5H QD 2H JC KS 4H KH 5S",
    "5C 2S JS 8D 9C 8C 3D AS KC AH",
    "JD 9S 2H QS 8H 5S 8C TH 5C 4C",
    "QC QS 8C 2S 2C 3S 9C 4C KS KH",
    "2D 5D 8S AH AD TD 2C JS KS 8C",
    "TC 5S 5H 8H QC 9H 6H JD 4H 9S",
    "3C JH 4H 9H AH 4S 2H 4C 8D AC",
    "8S TH 4D 7D 6D QD QS 7S TC 7C",
    "KH 6D 2D JD 5H JS QD JH 4H 4S",
    "9C 7S JH 4S 3S TS QC 8C TC 4H",
    "QH 9D 4D JH QS 3S 2C 7C 6C 2D",
    "4H 9S JD 5C 5H AH 9D TS 2D 4C",
    "KS JH TS 5D 2D AH JS 7H AS 8D",
    "JS AH 8C AD KS 5S 8H 2C 6C TH",
    "2H 5D AD AC KS 3D 8H TS 6H QC",
    "6D 4H TS 9C 5H JS JH 6S JD 4C",
    "JH QH 4H 2C 6D 3C 5D 4C QS KC",
    "6H 4H 6C 7H 6S 2S 8S KH QC 8C",
    "3H 3D 5D KS 4H TD AD 3S 4D TS",
    "5S 7C 8S 7D 2C KS 7S 6C 8C JS",
    "5D 2H 3S 7C 5C QD 5H 6D 9C 9H",
    "JS 2S KD 9S 8D TD TS AC 8C 9D",
    "5H QD 2S AC 8C 9H KS 7C 4S 3C",
    "KH AS 3H 8S 9C JS QS 4S AD 4D",
    "AS 2S TD AD 4D 9H JC 4C 5H QS",
    "5D 7C 4H TC 2D 6C JS 4S KC 3S",
    "4C 2C 5D AC 9H 3D JD 8S QS QH",
    "2C 8S 6H 3C QH 6D TC KD AC AH",
    "QC 6C 3S QS 4S AC 8D 5C AD KH",
    "5S 4C AC KH AS QC 2C 5C 8D 9C",
    "8H JD 3C KH 8D 5C 9C QD QH 9D",
    "7H TS 2C 8C 4S TD JC 9C 5H QH",
    "JS 4S 2C 7C TH 6C AS KS 7S JD",
    "JH 7C 9H 7H TC 5H 3D 6D 5D 4D",
    "2C QD JH 2H 9D 5S 3D TD AD KS",
    "JD QH 3S 4D TH 7D 6S QS KS 4H",
    "TC KS 5S 8D 8H AD 2S 2D 4C JH",
    "5S JH TC 3S 2D QS 9D 4C KD 9S",
    "AC KH 3H AS 9D KC 9H QD 6C 6S",
    "9H 7S 3D 5C 7D KC TD 8H 4H 6S",
    "3C 7H 8H TC QD 4D 7S 6S QH 6C",
    "6D AD 4C QD 6C 5D 7D 9D KS TS",
    "JH 2H JD 9S 7S TS KH 8D 5D 8H",
    "2D 9S 4C 7D 9D 5H QD 6D AC 6S",
    "7S 6D JC QD JH 4C 6S QS 2H 7D",
    "8C TD JH KD 2H 5C QS 2C JS 7S",
    "TC 5H 4H JH QD 3S 5S 5D 8S KH",
    "KS KH 7C 2C 5D JH 6S 9C 6D JC",
    "5H AH JD 9C JS KC 2H 6H 4D 5S",
    "AS 3C TH QC 6H 9C 8S 8C TD 7C",
    "KC 2C QD 9C KH 4D 7S 3C TS 9H",
    "9C QC 2S TS 8C TD 9S QD 3S 3C",
    "4D 9D TH JH AH 6S 2S JD QH JS",
    "QD 9H 6C KD 7D 7H 5D 6S 8H AH",
    "8H 3C 4S 2H 5H QS QH 7S 4H AC",
    "QS 3C 7S 9S 4H 3S AH KS 9D 7C",
    "AD 5S 6S 2H 2D 5H TC 4S 3C 8C",
    "QH TS 6S 4D JS KS JH AS 8S 6D",
    "2C 8S 2S TD 5H AS TC TS 6C KC",
    "KC TS 8H 2H 3H 7C 4C 5S TH TD",
    "KD AD KH 7H 7S 5D 5H 5S 2D 9C",
    "AD 9S 3D 7S 8C QC 7C 9C KD KS",
    "3C QC 9S 8C 4D 5C AS QD 6C 2C",
    "2H KC 8S JD 7S AC 8D 5C 2S 4D",
    "9D QH 3D 2S TC 3S KS 3C 9H TD",
    "KD 6S AC 2C 7H 5H 3S 6C 6H 8C",
    "QH TC 8S 6S KH TH 4H 5D TS 4D",
    "8C JS 4H 6H 2C 2H 7D AC QD 3D",
    "QS KC 6S 2D 5S 4H TD 3H JH 4C",
    "7S 5H 7H 8H KH 6H QS TH KD 7D",
    "5H AD KD 7C KH 5S TD 6D 3C 6C",
    "8C 9C 5H JD 7C KC KH 7H 2H 3S",
    "7S 4H AD 4D 8S QS TH 3D 7H 5S",
    "8D TC KS KD 9S 6D AD JD 5C 2S",
    "7H 8H 6C QD 2H 6H 9D TC 9S 7C",
    "8D 6D 4C 7C 6C 3C TH KH JS JH",
    "5S 3S 8S JS 9H AS AD 8H 7S KD",
    "JH 7C 2C KC 5H AS AD 9C 9S JS",
    "AD AC 2C 6S QD 7C 3H TH KS KD",
    "9D JD 4H 8H 4C KH 7S TS 8C KC",
    "3S 5S 2H 7S 6H 7D KS 5C 6D AD",
    "5S 8C 9H QS 7H 7S 2H 6C 7D TD",
    "QS 5S TD AC 9D KC 3D TC 2D 4D",
    "TD 2H 7D JD QD 4C 7H 5D KC 3D",
    "4C 3H 8S KD QH 5S QC 9H TC 5H",
    "9C QD TH 5H TS 5C 9H AH QH 2C",
    "4D 6S 3C AC 6C 3D 2C 2H TD TH",
    "AC 9C 5D QC 4D AD 8D 6D 8C KC",
    "AD 3C 4H AC 8D 8H 7S 9S TD JC",
    "4H 9H QH JS 2D TH TD TC KD KS",
    "5S 6S 9S 8D TH AS KH 5H 5C 8S",
    "JD 2S 9S 6S 5S 8S 5D 7S 7H 9D",
    "5D 8C 4C 9D AD TS 2C 7D KD TC",
    "8S QS 4D KC 5C 8D 4S KH JD KD",
    "AS 5C AD QH 7D 2H 9S 7H 7C TC",
    "2S 8S JD KH 7S 6C 6D AD 5D QC",
    "9H 6H 3S 8C 8H AH TC 4H JS TD",
    "2C TS 4D 7H 2D QC 9C 5D TH 7C",
    "6C 8H QC 5D TS JH 5C 5H 9H 4S",
    "2D QC 7H AS JS 8S 2H 4C 4H 8D",
    "JS 6S AC KD 3D 3C 4S 7H TH KC",
    "QH KH 6S QS 5S 4H 3C QD 3S 3H",
    "7H AS KH 8C 4H 9C 5S 3D 6S TS",
    "9C 7C 3H 5S QD 2C 3D AD AC 5H",
    "JH TD 2D 4C TS 3H KH AD 3S 7S",
    "AS 4C 5H 4D 6S KD JC 3C 6H 2D",
    "3H 6S 8C 2D TH 4S AH QH AD 5H",
    "7C 2S 9H 7H KC 5C 6D 5S 3H JC",
    "3C TC 9C 4H QD TD JH 6D 9H 5S",
    "7C 6S 5C 5D 6C 4S 7H 9H 6H AH",
    "AD 2H 7D KC 2C 4C 2S 9S 7H 3S",
    "TH 4C 8S 6S 3S AD KS AS JH TD",
    "5C TD 4S 4D AD 6S 5D TC 9C 7D",
    "8H 3S 4D 4S 5S 6H 5C AC 3H 3D",
    "9H 3C AC 4S QS 8S 9D QH 5H 4D",
    "JC 6C 5H TS AC 9C JD 8C 7C QD",
    "8S 8H 9C JD 2D QC QH 6H 3C 8D",
    "KS JS 2H 6H 5H QH QS 3H 7C 6D",
    "TC 3H 4S 7H QC 2H 3S 8C JS KH",
    "AH 8H 5S 4C 9H JD 3H 7S JC AC",
    "3C 2D 4C 5S 6C 4S QS 3S JD 3D",
    "5H 2D TC AH KS 6D 7H AD 8C 6H",
    "6C 7S 3C JD 7C 8H KS KH AH 6D",
    "AH 7D 3H 8H 8S 7H QS 5H 9D 2D",
    "JD AC 4H 7S 8S 9S KS AS 9D QH",
    "7S 2C 8S 5S JH QS JC AH KD 4C",
    "AH 2S 9H 4H 8D TS TD 6H QH JD",
    "4H JC 3H QS 6D 7S 9C 8S 9D 8D",
    "5H TD 4S 9S 4C 8C 8D 7H 3H 3D",
    "QS KH 3S 2C 2S 3C 7S TD 4S QD",
    "7C TD 4D 5S KH AC AS 7H 4C 6C",
    "2S 5H 6D JD 9H QS 8S 2C 2H TD",
    "2S TS 6H 9H 7S 4H JC 4C 5D 5S",
    "2C 5H 7D 4H 3S QH JC JS 6D 8H",
    "4C QH 7C QD 3S AD TH 8S 5S TS",
    "9H TC 2S TD JC 7D 3S 3D TH QH",
    "7D 4C 8S 5C JH 8H 6S 3S KC 3H",
    "JC 3H KH TC QH TH 6H 2C AC 5H",
    "QS 2H 9D 2C AS 6S 6C 2S 8C 8S",
    "9H 7D QC TH 4H KD QS AC 7S 3C",
    "4D JH 6S 5S 8H KS 9S QC 3S AS",
    "JD 2D 6S 7S TC 9H KC 3H 7D KD",
    "2H KH 7C 4D 4S 3H JS QD 7D KC",
    "4C JC AS 9D 3C JS 6C 8H QD 4D",
    "AH JS 3S 6C 4C 3D JH 6D 9C 9H",
    "9H 2D 8C 7H 5S KS 6H 9C 2S TC",
    "6C 8C AD 7H 6H 3D KH AS 5D TH",
    "KS 8C 3S TS 8S 4D 5S 9S 6C 4H",
    "9H 4S 4H 5C 7D KC 2D 2H 9D JH",
    "5C JS TC 9D 9H 5H 7S KH JC 6S",
    "7C 9H 8H 4D JC KH JD 2H TD TC",
    "8H 6C 2H 2C KH 6H 9D QS QH 5H",
    "AC 7D 2S 3D QD JC 2D 8D JD JH",
    "2H JC 2D 7H 2C 3C 8D KD TD 4H",
    "3S 4H 6D 8D TS 3H TD 3D 6H TH",
    "JH JC 3S AC QH 9H 7H 8S QC 2C",
    "7H TD QS 4S 8S 9C 2S 5D 4D 2H",
    "3D TS 3H 2S QC 8H 6H KC JC KS",
    "5D JD 7D TC 8C 6C 9S 3D 8D AC",
    "8H 6H JH 6C 5D 8D 8S 4H AD 2C",
    "9D 4H 2D 2C 3S TS AS TC 3C 5D",
    "4D TH 5H KS QS 6C 4S 2H 3D AD",
    "5C KC 6H 2C 5S 3C 4D 2D 9H 9S",
    "JD 4C 3H TH QH 9H 5S AH 8S AC",
    "7D 9S 6S 2H TD 9C 4H 8H QS 4C",
    "3C 6H 5D 4H 8C 9C KC 6S QD QS",
    "3S 9H KD TC 2D JS 8C 6S 4H 4S",
    "2S 4C 8S QS 6H KH 3H TH 8C 5D",
    "2C KH 5S 3S 7S 7H 6C 9D QD 8D",
    "8H KS AC 2D KH TS 6C JS KC 7H",
    "9C KS 5C TD QC AH 6C 5H 9S 7C",
    "5D 4D 3H 4H 6S 7C 7S AH QD TD",
    "2H 7D QC 6S TC TS AH 7S 9D 3H",
    "TH 5H QD 9S KS 7S 7C 6H 8C TD",
    "TH 2D 4D QC 5C 7D JD AH 9C 4H",
    "4H 3H AH 8D 6H QC QH 9H 2H 2C",
    "2D AD 4C TS 6H 7S TH 4H QS TD",
    "3C KD 2H 3H QS JD TC QC 5D 8H",
    "KS JC QD TH 9S KD 8D 8C 2D 9C",
    "3C QD KD 6D 4D 8D AH AD QC 8S",
    "8H 3S 9D 2S 3H KS 6H 4C 7C KC",
    "TH 9S 5C 3D 7D 6H AC 7S 4D 2C",
    "5C 3D JD 4D 2D 6D 5H 9H 4C KH",
    "AS 7H TD 6C 2H 3D QD KS 4C 4S",
    "JC 3C AC 7C JD JS 8H 9S QC 5D",
    "JD 6S 5S 2H AS 8C 7D 5H JH 3D",
    "8D TC 5S 9S 8S 3H JC 5H 7S AS",
    "5C TD 3D 7D 4H 8D 7H 4D 5D JS",
    "QS 9C KS TD 2S 8S 5C 2H 4H AS",
    "TH 7S 4H 7D 3H JD KD 5D 2S KC",
    "JD 7H 4S 8H 4C JS 6H QH 5S 4H",
    "2C QS 8C 5S 3H QC 2S 6C QD AD",
    "8C 3D JD TC 4H 2H AD 5S AC 2S",
    "5D 2C JS 2D AD 9D 3D 4C 4S JH",
    "8D 5H 5D 6H 7S 4D KS 9D TD JD",
    "3D 6D 9C 2S AS 7D 5S 5C 8H JD",
    "7C 8S 3S 6S 5H JD TC AD 7H 7S",
    "2S 9D TS 4D AC 8D 6C QD JD 3H",
    "9S KH 2C 3C AC 3D 5H 6H 8D 5D",
    "KS 3D 2D 6S AS 4C 2S 7C 7H KH",
    "AC 2H 3S JC 5C QH 4D 2D 5H 7S",
    "TS AS JD 8C 6H JC 8S 5S 2C 5D",
    "7S QH 7H 6C QC 8H 2D 7C JD 2S",
    "2C QD 2S 2H JC 9C 5D 2D JD JH",
    "7C 5C 9C 8S 7D 6D 8D 6C 9S JH",
    "2C AD 6S 5H 3S KS 7S 9D KH 4C",
    "7H 6C 2C 5C TH 9D 8D 3S QC AH",
    "5S KC 6H TC 5H 8S TH 6D 3C AH",
    "9C KD 4H AD TD 9S 4S 7D 6H 5D",
    "7H 5C 5H 6D AS 4C KD KH 4H 9D",
    "3C 2S 5C 6C JD QS 2H 9D 7D 3H",
    "AC 2S 6S 7S JS QD 5C QS 6H AD",
    "5H TH QC 7H TC 3S 7C 6D KC 3D",
    "4H 3D QC 9S 8H 2C 3S JC KS 5C",
    "4S 6S 2C 6H 8S 3S 3D 9H 3H JS",
    "4S 8C 4D 2D 8H 9H 7D 9D AH TS",
    "9S 2C 9H 4C 8D AS 7D 3D 6D 5S",
    "6S 4C 7H 8C 3H 5H JC AH 9D 9C",
    "2S 7C 5S JD 8C 3S 3D 4D 7D 6S",
    "3C KC 4S 5D 7D 3D JD 7H 3H 4H",
    "9C 9H 4H 4D TH 6D QD 8S 9S 7S",
    "2H AC 8S 4S AD 8C 2C AH 7D TC",
    "TS 9H 3C AD KS TC 3D 8C 8H JD",
    "QC 8D 2C 3C 7D 7C JD 9H 9C 6C",
    "AH 6S JS JH 5D AS QC 2C JD TD",
    "9H KD 2H 5D 2D 3S 7D TC AH TS",
    "TD 8H AS 5D AH QC AC 6S TC 5H",
    "KS 4S 7H 4D 8D 9C TC 2H 6H 3H",
    "3H KD 4S QD QH 3D 8H 8C TD 7S",
    "8S JD TC AH JS QS 2D KH KS 4D",
    "3C AD JC KD JS KH 4S TH 9H 2C",
    "QC 5S JS 9S KS AS 7C QD 2S JD",
    "KC 5S QS 3S 2D AC 5D 9H 8H KS",
    "6H 9C TC AD 2C 6D 5S JD 6C 7C",
    "QS KH TD QD 2C 3H 8S 2S QC AH",
    "9D 9H JH TC QH 3C 2S JS 5C 7H",
    "6C 3S 3D 2S 4S QD 2D TH 5D 2C",
    "2D 6H 6D 2S JC QH AS 7H 4H KH",
    "5H 6S KS AD TC TS 7C AC 4S 4H",
    "AD 3C 4H QS 8C 9D KS 2H 2D 4D",
    "4S 9D 6C 6D 9C AC 8D 3H 7H KD",
    "JC AH 6C TS JD 6D AD 3S 5D QD",
    "JC JH JD 3S 7S 8S JS QC 3H 4S",
    "JD TH 5C 2C AD JS 7H 9S 2H 7S",
    "8D 3S JH 4D QC AS JD 2C KC 6H",
    "2C AC 5H KD 5S 7H QD JH AH 2D",
    "JC QH 8D 8S TC 5H 5C AH 8C 6C",
    "3H JS 8S QD JH 3C 4H 6D 5C 3S",
    "6D 4S 4C AH 5H 5S 3H JD 7C 8D",
    "8H AH 2H 3H JS 3C 7D QC 4H KD",
    "6S 2H KD 5H 8H 2D 3C 8S 7S QD",
    "2S 7S KC QC AH TC QS 6D 4C 8D",
    "5S 9H 2C 3S QD 7S 6C 2H 7C 9D",
    "3C 6C 5C 5S JD JC KS 3S 5D TS",
    "7C KS 6S 5S 2S 2D TC 2H 5H QS",
    "AS 7H 6S TS 5H 9S 9D 3C KD 2H",
    "4S JS QS 3S 4H 7C 2S AC 6S 9D",
    "8C JH 2H 5H 7C 5D QH QS KH QC",
    "3S TD 3H 7C KC 8D 5H 8S KH 8C",
    "4H KH JD TS 3C 7H AS QC JS 5S",
    "AH 9D 2C 8D 4D 2D 6H 6C KC 6S",
    "2S 6H 9D 3S 7H 4D KH 8H KD 3D",
    "9C TC AC JH KH 4D JD 5H TD 3S",
    "7S 4H 9D AS 4C 7D QS 9S 2S KH",
    "3S 8D 8S KS 8C JC 5C KH 2H 5D",
    "8S QH 2C 4D KC JS QC 9D AC 6H",
    "8S 8C 7C JS JD 6S 4C 9C AC 4S",
    "QH 5D 2C 7D JC 8S 2D JS JH 4C",
    "JS 4C 7S TS JH KC KH 5H QD 4S",
    "QD 8C 8D 2D 6S TD 9D AC QH 5S",
    "QH QC JS 3D 3C 5C 4H KH 8S 7H",
    "7C 2C 5S JC 8S 3H QC 5D 2H KC",
    "5S 8D KD 6H 4H QD QH 6D AH 3D",
    "7S KS 6C 2S 4D AC QS 5H TS JD",
    "7C 2D TC 5D QS AC JS QC 6C KC",
    "2C KS 4D 3H TS 8S AD 4H 7S 9S",
    "QD 9H QH 5H 4H 4D KH 3S JC AD",
    "4D AC KC 8D 6D 4C 2D KH 2C JD",
    "2C 9H 2D AH 3H 6D 9C 7D TC KS",
    "8C 3H KD 7C 5C 2S 4S 5H AS AH",
    "TH JD 4H KD 3H TC 5C 3S AC KH",
    "6D 7H AH 7S QC 6H 2D TD JD AS",
    "JH 5D 7H TC 9S 7D JC AS 5S KH",
    "2H 8C AD TH 6H QD KD 9H 6S 6C",
    "QH KC 9D 4D 3S JS JH 4H 2C 9H",
    "TC 7H KH 4H JC 7D 9S 3H QS 7S",
    "AD 7D JH 6C 7H 4H 3S 3H 4D QH",
    "JD 2H 5C AS 6C QC 4D 3C TC JH",
    "AC JD 3H 6H 4C JC AD 7D 7H 9H",
    "4H TC TS 2C 8C 6S KS 2H JD 9S",
    "4C 3H QS QC 9S 9H 6D KC 9D 9C",
    "5C AD 8C 2C QH TH QD JC 8D 8H",
    "QC 2C 2S QD 9C 4D 3S 8D JH QS",
    "9D 3S 2C 7S 7C JC TD 3C TC 9H",
    "3C TS 8H 5C 4C 2C 6S 8D 7C 4H",
    "KS 7H 2H TC 4H 2C 3S AS AH QS",
    "8C 2D 2H 2C 4S 4C 6S 7D 5S 3S",
    "TH QC 5D TD 3C QS KD KC KS AS",
    "4D AH KD 9H KS 5C 4C 6H JC 7S",
    "KC 4H 5C QS TC 2H JC 9S AH QH",
    "4S 9H 3H 5H 3C QD 2H QC JH 8H",
    "5D AS 7H 2C 3D JH 6H 4C 6S 7D",
    "9C JD 9H AH JS 8S QH 3H KS 8H",
    "3S AC QC TS 4D AD 3D AH 8S 9H",
    "7H 3H QS 9C 9S 5H JH JS AH AC",
    "8D 3C JD 2H AC 9C 7H 5S 4D 8H",
    "7C JH 9H 6C JS 9S 7H 8C 9D 4H",
    "2D AS 9S 6H 4D JS JH 9H AD QD",
    "6H 7S JH KH AH 7H TD 5S 6S 2C",
    "8H JH 6S 5H 5S 9D TC 4C QC 9S",
    "7D 2C KD 3H 5H AS QD 7H JS 4D",
    "TS QH 6C 8H TH 5H 3C 3H 9C 9D",
    "AD KH JS 5D 3H AS AC 9S 5C KC",
    "2C KH 8C JC QS 6D AH 2D KC TC",
    "9D 3H 2S 7C 4D 6D KH KS 8D 7D",
    "9H 2S TC JH AC QC 3H 5S 3S 8H",
    "3S AS KD 8H 4C 3H 7C JH QH TS",
    "7S 6D 7H 9D JH 4C 3D 3S 6C AS",
    "4S 2H 2C 4C 8S 5H KC 8C QC QD",
    "3H 3S 6C QS QC 2D 6S 5D 2C 9D",
    "2H 8D JH 2S 3H 2D 6C 5C 7S AD",
    "9H JS 5D QH 8S TS 2H 7S 6S AD",
    "6D QC 9S 7H 5H 5C 7D KC JD 4H",
    "QC 5S 9H 9C 4D 6S KS 2S 4C 7C",
    "9H 7C 4H 8D 3S 6H 5C 8H JS 7S",
    "2D 6H JS TD 4H 4D JC TH 5H KC",
    "AC 7C 8D TH 3H 9S 2D 4C KC 4D",
    "KD QS 9C 7S 3D KS AD TS 4C 4H",
    "QH 9C 8H 2S 7D KS 7H 5D KD 4C",
    "9C 2S 2H JC 6S 6C TC QC JH 5C",
    "7S AC 8H KC 8S 6H QS JC 3D 6S",
    "JS 2D JH 8C 4S 6H 8H 6D 5D AD",
    "6H 7D 2S 4H 9H 7C AS AC 8H 5S",
    "3C JS 4S 6D 5H 2S QH 6S 9C 2C",
    "3D 5S 6S 9S 4C QS 8D QD 8S TC",
    "9C 3D AH 9H 5S 2C 7D AD JC 3S",
    "7H TC AS 3C 6S 6D 7S KH KC 9H",
    "3S TC 8H 6S 5H JH 8C 7D AC 2S",
    "QD 9D 9C 3S JC 8C KS 8H 5D 4D",
    "JS AH JD 6D 9D 8C 9H 9S 8H 3H",
    "2D 6S 4C 4D 8S AD 4S TC AH 9H",
    "TS AC QC TH KC 6D 4H 7S 8C 2H",
    "3C QD JS 9D 5S JC AH 2H TS 9H",
    "3H 4D QH 5D 9C 5H 7D 4S JC 3S",
    "8S TH 3H 7C 2H JD JS TS AC 8D",
    "9C 2H TD KC JD 2S 8C 5S AD 2C",
    "3D KD 7C 5H 4D QH QD TC 6H 7D",
    "7H 2C KC 5S KD 6H AH QC 7S QH",
    "6H 5C AC 5H 2C 9C 2D 7C TD 2S",
    "4D 9D AH 3D 7C JD 4H 8C 4C KS",
    "TH 3C JS QH 8H 4C AS 3D QS QC",
    "4D 7S 5H JH 6D 7D 6H JS KH 3C",
    "QD 8S 7D 2H 2C 7C JC 2S 5H 8C",
    "QH 8S 9D TC 2H AD 7C 8D QD 6S",
    "3S 7C AD 9H 2H 9S JD TS 4C 2D",
    "3S AS 4H QC 2C 8H 8S 7S TD TC",
    "JH TH TD 3S 4D 4H 5S 5D QS 2C",
    "8C QD QH TC 6D 4S 9S 9D 4H QC",
    "8C JS 9D 6H JD 3H AD 6S TD QC",
    "KC 8S 3D 7C TD 7D 8D 9H 4S 3S",
    "6C 4S 3D 9D KD TC KC KS AC 5S",
    "7C 6S QH 3D JS KD 6H 6D 2D 8C",
    "JD 2S 5S 4H 8S AC 2D 6S TS 5C",
    "5H 8C 5S 3C 4S 3D 7C 8D AS 3H",
    "AS TS 7C 3H AD 7D JC QS 6C 6H",
    "3S 9S 4C AC QH 5H 5D 9H TS 4H",
    "6C 5C 7H 7S TD AD JD 5S 2H 2S",
    "7D 6C KC 3S JD 8D 8S TS QS KH",
    "8S QS 8D 6C TH AC AH 2C 8H 9S",
    "7H TD KH QH 8S 3D 4D AH JD AS",
    "TS 3D 2H JC 2S JH KH 6C QC JS",
    "KC TH 2D 6H 7S 2S TC 8C 9D QS",
    "3C 9D 6S KH 8H 6D 5D TH 2C 2H",
    "6H TC 7D AD 4D 8S TS 9H TD 7S",
    "JS 6D JD JC 2H AC 6C 3D KH 8D",
    "KH JD 9S 5D 4H 4C 3H 7S QS 5C",
    "4H JD 5D 3S 3C 4D KH QH QS 7S",
    "JD TS 8S QD AH 4C 6H 3S 5S 2C",
    "QS 3D JD AS 8D TH 7C 6S QC KS",
    "7S 2H 8C QC 7H AC 6D 2D TH KH",
    "5S 6C 7H KH 7D AH 8C 5C 7S 3D",
    "3C KD AD 7D 6C 4D KS 2D 8C 4S",
    "7C 8D 5S 2D 2S AH AD 2C 9D TD",
    "3C AD 4S KS JH 7C 5C 8C 9C TH",
    "AS TD 4D 7C JD 8C QH 3C 5H 9S",
    "3H 9C 8S 9S 6S QD KS AH 5H JH",
    "QC 9C 5S 4H 2H TD 7D AS 8C 9D",
    "8C 2C 9D KD TC 7S 3D KH QC 3C",
    "4D AS 4C QS 5S 9D 6S JD QH KS",
    "6D AH 6C 4C 5H TS 9H 7D 3D 5S",
    "QS JD 7C 8D 9C AC 3S 6S 6C KH",
    "8H JH 5D 9S 6D AS 6S 3S QC 7H",
    "QD AD 5C JH 2H AH 4H AS KC 2C",
    "JH 9C 2C 6H 2D JS 5D 9H KC 6D",
    "7D 9D KD TH 3H AS 6S QC 6H AD",
    "JD 4H 7D KC 3H JS 3C TH 3D QS",
    "4C 3H 8C QD 5H 6H AS 8H AD JD",
    "TH 8S KD 5D QC 7D JS 5S 5H TS",
    "7D KC 9D QS 3H 3C 6D TS 7S AH",
    "7C 4H 7H AH QC AC 4D 5D 6D TH",
    "3C 4H 2S KD 8H 5H JH TC 6C JD",
    "4S 8C 3D 4H JS TD 7S JH QS KD",
    "7C QC KD 4D 7H 6S AD TD TC KH",
    "5H 9H KC 3H 4D 3D AD 6S QD 6H",
    "TH 7C 6H TS QH 5S 2C KC TD 6S",
    "7C 4D 5S JD JH 7D AC KD KH 4H",
    "7D 6C 8D 8H 5C JH 8S QD TH JD",
    "8D 7D 6C 7C 9D KD AS 5C QH JH",
    "9S 2C 8C 3C 4C KS JH 2D 8D 4H",
    "7S 6C JH KH 8H 3H 9D 2D AH 6D",
    "4D TC 9C 8D 7H TD KS TH KD 3C",
    "JD 9H 8D QD AS KD 9D 2C 2S 9C",
    "8D 3H 5C 7H KS 5H QH 2D 8C 9H",
    "2D TH 6D QD 6C KC 3H 3S AD 4C",
    "4H 3H JS 9D 3C TC 5H QH QC JC",
    "3D 5C 6H 3S 3C JC 5S 7S 2S QH",
    "AC 5C 8C 4D 5D 4H 2S QD 3C 3H",
    "2C TD AH 9C KD JS 6S QD 4C QC",
    "QS 8C 3S 4H TC JS 3H 7C JC AD",
    "5H 4D 9C KS JC TD 9S TS 8S 9H",
    "QD TS 7D AS AC 2C TD 6H 8H AH",
    "6S AD 8C 4S 9H 8D 9D KH 8S 3C",
    "QS 4D 2D 7S KH JS JC AD 4C 3C",
    "QS 9S 7H KC TD TH 5H JS AC JH",
    "6D AC 2S QS 7C AS KS 6S KH 5S",
    "6D 8H KH 3C QS 2H 5C 9C 9D 6C",
    "JS 2C 4C 6H 7D JC AC QD TD 3H",
    "4H QC 8H JD 4C KD KS 5C KC 7S",
    "6D 2D 3H 2S QD 5S 7H AS TH 6S",
    "AS 6D 8D 2C 8S TD 8H QD JC AH",
    "9C 9H 2D TD QH 2H 5C TC 3D 8H",
    "KC 8S 3D KH 2S TS TC 6S 4D JH",
    "9H 9D QS AC KC 6H 5D 4D 8D AH",
    "9S 5C QS 4H 7C 7D 2H 8S AD JS",
    "3D AC 9S AS 2C 2D 2H 3H JC KH",
    "7H QH KH JD TC KS 5S 8H 4C 8D",
    "2H 7H 3S 2S 5H QS 3C AS 9H KD",
    "AD 3D JD 6H 5S 9C 6D AC 9S 3S",
    "3D 5D 9C 2D AC 4S 2S AD 6C 6S",
    "QC 4C 2D 3H 6S KC QH QD 2H JH",
    "QC 3C 8S 4D 9S 2H 5C 8H QS QD",
    "6D KD 6S 7H 3S KH 2H 5C JC 6C",
    "3S 9S TC 6S 8H 2D AD 7S 8S TS",
    "3C 6H 9C 3H 5C JC 8H QH TD QD",
    "3C JS QD 5D TD 2C KH 9H TH AS",
    "9S TC JD 3D 5C 5H AD QH 9H KC",
    "TC 7H 4H 8H 3H TD 6S AC 7C 2S",
    "QS 9D 5D 3C JC KS 4D 6C JH 2S",
    "9S 6S 3C 7H TS 4C KD 6D 3D 9C",
    "2D 9H AH AC 7H 2S JH 3S 7C QC",
    "QD 9H 3C 2H AC AS 8S KD 8C KH",
    "2D 7S TD TH 6D JD 8D 4D 2H 5S",
    "8S QH KD JD QS JH 4D KC 5H 3S",
    "3C KH QC 6D 8H 3S AH 7D TD 2D",
    "5S 9H QH 4S 6S 6C 6D TS TH 7S",
    "6C 4C 6D QS JS 9C TS 3H 8D 8S",
    "JS 5C 7S AS 2C AH 2H AD 5S TC",
    "KD 6C 9C 9D TS 2S JC 4H 2C QD",
    "QS 9H TC 3H KC KS 4H 3C AD TH",
    "KH 9C 2H KD 9D TC 7S KC JH 2D",
    "7C 3S KC AS 8C 5D 9C 9S QH 3H",
    "2D 8C TD 4C 2H QC 5D TC 2C 7D",
    "KS 4D 6C QH TD KH 5D 7C AD 8D",
    "2S 9S 8S 4C 8C 3D 6H QD 7C 7H",
    "6C 8S QH 5H TS 5C 3C 4S 2S 2H",
    "8S 6S 2H JC 3S 3H 9D 8C 2S 7H",
    "QC 2C 8H 9C AC JD 4C 4H 6S 3S",
    "3H 3S 7D 4C 9S 5H 8H JC 3D TC",
    "QH 2S 2D 9S KD QD 9H AD 6D 9C",
    "8D 2D KS 9S JC 4C JD KC 4S TH",
    "KH TS 6D 4D 5C KD 5H AS 9H AD",
    "QD JS 7C 6D 5D 5C TH 5H QH QS",
    "9D QH KH 5H JH 4C 4D TC TH 6C",
    "KH AS TS 9D KD 9C 7S 4D 8H 5S",
    "KH AS 2S 7D 9D 4C TS TH AH 7C",
    "KS 4D AC 8S 9S 8D TH QH 9D 5C",
    "5D 5C 8C QS TC 4C 3D 3S 2C 8D",
    "9D KS 2D 3C KC 4S 8C KH 6C JC",
    "8H AH 6H 7D 7S QD 3C 4C 6C KC",
    "3H 2C QH 8H AS 7D 4C 8C 4H KC",
    "QD 5S 4H 2C TD AH JH QH 4C 8S",
    "3H QS 5S JS 8H 2S 9H 9C 3S 2C",
    "6H TS 7S JC QD AC TD KC 5S 3H",
    "QH AS QS 7D JC KC 2C 4C 5C 5S",
    "QH 3D AS JS 4H 8D 7H JC 2S 9C",
    "5D 4D 2S 4S 9D 9C 2D QS 8H 7H",
    "6D 7H 3H JS TS AC 2D JH 7C 8S",
    "JH 5H KC 3C TC 5S 9H 4C 8H 9D",
    "8S KC 5H 9H AD KS 9D KH 8D AH",
    "JC 2H 9H KS 6S 3H QC 5H AH 9C",
    "5C KH 5S AD 6C JC 9H QC 9C TD",
    "5S 5D JC QH 2D KS 8H QS 2H TS",
    "JH 5H 5S AH 7H 3C 8S AS TD KH",
    "6H 3D JD 2C 4C KC 7S AH 6C JH",
    "4C KS 9D AD 7S KC 7D 8H 3S 9C",
    "7H 5C 5H 3C 8H QC 3D KH 6D JC",
    "2D 4H 5D 7D QC AD AH 9H QH 8H",
    "KD 8C JS 9D 3S 3C 2H 5D 6D 2S",
    "8S 6S TS 3C 6H 8D 5S 3H TD 6C",
    "KS 3D JH 9C 7C 9S QS 5S 4H 6H",
    "7S 6S TH 4S KC KD 3S JC JH KS",
    "7C 3C 2S 6D QH 2C 7S 5H 8H AH",
    "KC 8D QD 6D KH 5C 7H 9D 3D 9C",
    "6H 2D 8S JS 9S 2S 6D KC 7C TC",
    "KD 9C JH 7H KC 8S 2S 7S 3D 6H",
    "4H 9H 2D 4C 8H 7H 5S 8S 2H 8D",
    "AD 7C 3C 7S 5S 4D 9H 3D JC KH",
    "5D AS 7D 6D 9C JC 4C QH QS KH",
    "KD JD 7D 3D QS QC 8S 6D JS QD",
    "6S 8C 5S QH TH 9H AS AC 2C JD",
    "QC KS QH 7S 3C 4C 5C KC 5D AH",
    "6C 4H 9D AH 2C 3H KD 3D TS 5C",
    "TD 8S QS AS JS 3H KD AC 4H KS",
    "7D 5D TS 9H 4H 4C 9C 2H 8C QC",
    "2C 7D 9H 4D KS 4C QH AD KD JS",
    "QD AD AH KH 9D JS 9H JC KD JD",
    "8S 3C 4S TS 7S 4D 5C 2S 6H 7C",
    "JS 7S 5C KD 6D QH 8S TD 2H 6S",
    "QH 6C TC 6H TD 4C 9D 2H QC 8H",
    "3D TS 4D 2H 6H 6S 2C 7H 8S 6C",
    "9H 9D JD JH 3S AH 2C 6S 3H 8S",
    "2C QS 8C 5S 3H 2S 7D 3C AD 4S",
    "5C QC QH AS TS 4S 6S 4C 5H JS",
    "JH 5C TD 4C 6H JS KD KH QS 4H",
    "TC KH JC 4D 9H 9D 8D KC 3C 8H",
    "2H TC 8S AD 9S 4H TS 7H 2C 5C",
    "4H 2S 6C 5S KS AH 9C 7C 8H KD",
    "TS QH TD QS 3C JH AH 2C 8D 7D",
    "5D KC 3H 5S AC 4S 7H QS 4C 2H",
    "3D 7D QC KH JH 6D 6C TD TH KD",
    "5S 8D TH 6C 9D 7D KH 8C 9S 6D",
    "JD QS 7S QC 2S QH JC 4S KS 8D",
    "7S 5S 9S JD KD 9C JC AD 2D 7C",
    "4S 5H AH JH 9C 5D TD 7C 2D 6S",
    "KC 6C 7H 6S 9C QD 5S 4H KS TD",
    "6S 8D KS 2D TH TD 9H JD TS 3S",
    "KH JS 4H 5D 9D TC TD QC JD TS",
    "QS QD AC AD 4C 6S 2D AS 3H KC",
    "4C 7C 3C TD QS 9C KC AS 8D AD",
    "KC 7H QC 6D 8H 6S 5S AH 7S 8C",
    "3S AD 9H JC 6D JD AS KH 6S JH",
    "AD 3D TS KS 7H JH 2D JS QD AC",
    "9C JD 7C 6D TC 6H 6C JC 3D 3S",
    "QC KC 3S JC KD 2C 8D AH QS TS",
    "AS KD 3D JD 8H 7C 8C 5C QD 6C",
];
Problem 55 "Lychrel numbers"

If we take 47, reverse and add, 47 + 74 = 121, which is palindromic.

Not all numbers produce palindromes so quickly. For example,

349 + 943 = 1292,
1292 + 2921 = 4213
4213 + 3124 = 7337

That is, 349 took three iterations to arrive at a palindrome.

Although no one has proved it yet, it is thought that some numbers, like 196, never produce a palindrome. A number that never forms a palindrome through the reverse and add process is called a Lychrel number. Due to the theoretical nature of these numbers, and for the purpose of this problem, we shall assume that a number is Lychrel until proven otherwise. In addition you are given that for every number below ten-thousand, it will either (i) become a palindrome in less than fifty iterations, or, (ii) no one, with all the computing power that exists, has managed so far to map it to a palindrome. In fact, 10677 is the first number to be shown to require over fifty iterations before producing a palindrome: 4668731596684224866951378664 (53 iterations, 28-digits).

Surprisingly, there are palindromic numbers that are themselves Lychrel numbers; the first example is 4994.

How many Lychrel numbers are there below ten-thousand?

NOTE: Wording was modified slightly on 24 April 2007 to emphasise the theoretical nature of Lychrel numbers.

問 55 「Lychrel数」

47とその反転を足し合わせると, 47 + 74 = 121となり, 回文数になる.

全ての数が素早く回文数になるわけではない. 349を考えよう,

  • 349 + 943 = 1292
  • 1292 + 2921 = 4213
  • 4213 + 3124 = 7337

349は, 3回の操作を経て回文数になる.

まだ証明はされていないが, 196のようないくつかの数字は回文数にならないと考えられている.

反転したものを足すという操作を経ても回文数にならないものをLychrel数と呼ぶ.

先のような数の理論的な性質により, またこの問題の目的のために, Lychrel数で無いと証明されていない数はLychrel数だと仮定する.

更に, 10000未満の数については,常に以下のどちらか一方が成り立つと仮定してよい.

  1. 50回未満の操作で回文数になる
  2. まだ誰も回文数まで到達していない

実際, 10677が50回以上の操作を必要とする最初の数である: 4668731596684224866951378664 (53回の操作で28桁のこの回文数になる).

驚くべきことに, 回文数かつLychrel数であるものが存在する. 最初の数は4994である.

10000未満のLychrel数の個数を答えよ.

fn merge_each_other(num: &mut Vec<u8>, rev: &mut Vec<u8>) {
    let mut carry = 0u8;
    rev.iter().zip(num.iter_mut()).for_each(|(&r, d)| {
        let s = r + *d + carry;
        *d = s % 10;
        carry = s / 10;
    });
    if carry != 0 {
        num.push(carry);
        rev.push(0);
    }
    num.iter()
        .rev()
        .zip(rev.iter_mut())
        .for_each(|(&d, r)| *r = d);
}

fn symmetric_digit_vector_pair(mut n: u32, num: &mut Vec<u8>, rev: &mut Vec<u8>) {
    num.clear();
    rev.clear();
    while n > 0 {
        let d = (n % 10) as u8;
        rev.push(d);
        n /= 10;
    }
    rev.iter().rev().for_each(|&d| num.push(d));
}

fn main() {
    let mut count = 0u32;
    let mut num = Vec::with_capacity(56);
    let mut rev = Vec::with_capacity(56);
    'next_num: for n in 10u32..10_000 {
        symmetric_digit_vector_pair(n, &mut num, &mut rev);
        for _ in 0..50 {
            merge_each_other(&mut num, &mut rev);
            if rev == num {
                continue 'next_num;
            }
        }
        count += 1;
    }

    println!("{}", count);
    assert_eq!(count, 249);
}

use std::collections::LinkedList;

fn merge_each_other(num: &mut LinkedList<u8>, rev: &mut LinkedList<u8>) {
    let mut carry = 0u8;
    rev.iter().zip(num.iter_mut()).for_each(|(&r, d)| {
        let s = r + *d + carry;
        *d = s % 10;
        carry = s / 10;
    });
    if carry != 0 {
        num.push_back(carry);
        rev.push_back(0);
    }
    num.iter()
        .rev()
        .zip(rev.iter_mut())
        .for_each(|(&d, r)| *r = d);
}

fn symmetric_digit_vector_pair(mut n: u32) -> (LinkedList<u8>, LinkedList<u8>) {
    let mut rev = LinkedList::new();
    while n > 0 {
        let d = (n % 10) as u8;
        rev.push_back(d);
        n /= 10;
    }
    let num = rev.iter().rev().map(|&d| d).collect::<LinkedList<u8>>();
    (num, rev)
}

fn main() {
    let mut count = 0u32;
    'next_num: for n in 10u32..10_000 {
        let (mut num, mut rev) = symmetric_digit_vector_pair(n);
        for _ in 0..50 {
            merge_each_other(&mut num, &mut rev);
            if rev == num {
                continue 'next_num;
            }
        }
        count += 1;
    }

    println!("{}", count);
    assert_eq!(count, 249);
}
Problem 56 "Powerful digit sum"

A googol (10100) is a massive number: one followed by one-hundred zeros; 100100 is almost unimaginably large: one followed by two-hundred zeros. Despite their size, the sum of the digits in each number is only 1.

Considering natural numbers of the form, ab, where a, b < 100, what is the maximum digital sum?

問 56 「もっとべき乗の数字和」

Googol \(10^{100}\)は非常に大きな数である: 1の後に0が100個続く. \(100^{100}\)は想像を絶する. 1の後に0が200回続く. その大きさにも関わらず, 両者とも数字和 ( 桁の和 ) は1である.

a, b < 100 について自然数 \(a^{b}\) を考える. 数字和の最大値を答えよ.

struct BigNum {
    _v: Vec<u64>,
}

impl BigNum {
    const TEN_MIL: u64 = 10_000_000_000;
    fn new() -> Self {
        BigNum {
            _v: vec![],
        }
    }
    fn init(&mut self, base: u8) {
        self._v.clear();
        self._v.push(base as u64);
    }
    fn multiply(&mut self, n: u8) {
        let mut carry = 0u64;
        for con in self._v.iter_mut() {
            *con = *con * n as u64 + carry;
            if *con < Self::TEN_MIL {
                carry = 0;
                continue;
            }
            carry = *con / Self::TEN_MIL;
            *con %= Self::TEN_MIL;
        }
        if carry != 0 {
            self._v.push(carry);
        }
    }
    fn digit_sum(&self) -> u32 {
        let mut sum = 0u32;
        for &con in &self._v {
            let mut t = con;
            while t > 0 {
                sum += (t % 10) as u32;
                t /= 10;
            }
        }
        sum
    }
}

fn main() {
    let mut bignum = BigNum::new();
    let mut max = 0u32;
    for a in 2u8..100 {
        if a % 10 == 0 {
            continue;
        }
        bignum.init(a);
        for _ in 2u8..100 {
            bignum.multiply(a);
            max = std::cmp::max(max, bignum.digit_sum());
        }
    }

    println!("{}", max);
    assert_eq!(max, 972);
}

struct BigNum {
    _v: Vec<u64>,
}

impl BigNum {
    const TEN_MIL: u64 = 10_000_000_000;
    fn new() -> Self {
        BigNum {
            _v: vec![],
        }
    }
    fn compute(&mut self, base: u8, exp: u8) {
        self._v.clear();
        self._v.push(1);
        for _ in 0..exp {
            self._multiply(base as u64);
        }
    }
    fn _multiply(&mut self, n: u64) {
        let mut carry = 0u64;
        for con in self._v.iter_mut() {
            *con = *con * n + carry;
            if *con < Self::TEN_MIL {
                carry = 0;
                continue;
            }
            carry = *con / Self::TEN_MIL;
            *con %= Self::TEN_MIL;
        }
        if carry != 0 {
            self._v.push(carry);
        }
    }
    fn digit_sum(&self) -> u32 {
        let mut sum = 0u32;
        for &con in &self._v {
            let mut t = con;
            while t > 0 {
                sum += (t % 10) as u32;
                t /= 10;
            }
        }
        sum
    }
}

fn main() {
    let mut bignum = BigNum::new();
    let mut max = 0u32;
    for a in 2u8..100 {
        if a % 10 == 0 {
            continue;
        }
        for b in 2u8..100 {
            bignum.compute(a, b);
            max = std::cmp::max(max, bignum.digit_sum());
        }
    }

    println!("{}", max);
    assert_eq!(max, 972);
}
Prombem 57 "Square root convergents"

It is possible to show that the square root of two can be expressed as an infinite continued fraction.

$$\sqrt 2 =1+ \frac 1 {2+ \frac 1 {2 +\frac 1 {2+ \dots}}}$$

By expanding this for the first four iterations, we get:

$$1 + \frac 1 2 = \frac 32 = 1.5$$
$$1 + \frac 1 {2 + \frac 1 2} = \frac 7 5 = 1.4$$
$$1 + \frac 1 {2 + \frac 1 {2+\frac 1 2}} = \frac {17}{12} = 1.41666 \dots$$
$$1 + \frac 1 {2 + \frac 1 {2+\frac 1 {2+\frac 1 2}}} = \frac {41}{29} = 1.41379 \dots$$

The next three expansions are \(\frac{99}{70}\), \(\frac {239}{169}\), and \(\frac {577}{408}\), but the eighth expansion, \(\frac {1393}{985}\), is the first example where the number of digits in the numerator exceeds the number of digits in the denominator.

In the first one-thousand expansions, how many fractions contain a numerator with more digits than the denominator?

問 57 「平方根の近似分数」

2の平方根は無限に続く連分数で表すことができる.

最初の4回の繰り返しを展開すると以下が得られる.

次の3つの項は99/70, 239/169, 577/408である. 第8項は1393/985である. これは分子の桁数が分母の桁数を超える最初の例である.

最初の1000項を考えたとき, 分子の桁数が分母の桁数を超える項はいくつあるか?

struct Fraction {
    deno_prev: u64,
    deno: u64,
    nume: u64,
    n: u32,
}

impl Fraction {
    fn new() -> Self {
        let deno_prev = 2u64;
        let deno = 5u64;
        Self {
            deno_prev,
            deno,
            nume: deno_prev + deno,
            n: 2,
        }
    }
    fn increment(&mut self) {
        self.n += 1;
        self.deno_prev = self.deno;
        self.deno += self.nume;
        self.nume = self.deno_prev + self.deno;
        const THRESHOLD: u64 = {
            let mut threshold = 1u64;
            while threshold < u64::MAX / 100 {
                threshold *= 10;
            }
            threshold
        };
        if self.deno > THRESHOLD && self.nume > THRESHOLD {
            self.deno /= 10;
            self.nume /= 10;
        }
    }
    fn has_numerator_more_digits(&self) -> bool {
        let mut n = self.nume;
        let mut d = self.deno;
        while n > 0 && d > 0 {
            n /= 10;
            d /= 10;
        }
        n > d
    }
}

fn main() {
    let mut count = 0u32;
    let mut frac = Fraction::new();
    while {
        if frac.has_numerator_more_digits() {
            count += 1;
        }
        frac.increment();
        frac.n <= 1000
    } {}

    println!("{}", count);
    assert_eq!(count, 153);
}

#[derive(Clone)]
struct BigNum {
    v: Vec<u64>,
}

impl BigNum {
    const TEN_MIL: u64 = 10_000_000_000;
    fn new(n: u8) -> Self {
        Self { v: vec![n as u64] }
    }
    fn merge(&mut self, page: usize, n: u64, carry: &mut u64) {
        if self.v.get(page).is_none() {
            self.v.push(0u64)
        }
        if let Some(con) = self.v.get_mut(page) {
            *con += n + *carry;
            if *con < Self::TEN_MIL {
                *carry = 0;
                return;
            }
            *carry = 1;
            *con -= Self::TEN_MIL;
        }
    }
    fn double(&mut self) -> &Self {
        let mut carry = 0u64;
        for con in self.v.iter_mut() {
            *con *= 2;
            *con += carry;
            if *con < Self::TEN_MIL {
                carry = 0;
                continue;
            }
            carry = 1;
            *con -= Self::TEN_MIL;
        }
        if carry != 0 {
            self.v.push(1u64);
        }
        self
    }
    fn add(&mut self, b: &BigNum) {
        let mut p = 0usize;
        let mut carry = 0u64;
        let mut ite = b.v.iter();
        while let Some(n) = ite.next() {
            self.merge(p, *n, &mut carry);
            p += 1;
        }
        while carry != 0 {
            self.merge(p, 0, &mut carry);
            p += 1;
        }
    }
}

struct Fraction {
    deno: BigNum,
    nume: BigNum,
    n: u32,
}

impl Fraction {
    fn new() -> Self {
        Self {
            deno: BigNum::new(5),
            nume: BigNum::new(7),
            n: 2,
        }
    }
    fn increment(&mut self) {
        self.n += 1;
        let t = self.nume.clone();
        self.nume.add(self.deno.clone().double());
        self.deno.add(&t);
    }
    fn has_numerator_more_digits(&self) -> bool {
        if self.nume.v.len() != self.deno.v.len() {
            return self.nume.v.len() > self.deno.v.len();
        }
        let mut n = *self.nume.v.last().expect("BigNum must have a container");
        let mut d = *self.deno.v.last().expect("BigNum must have a container");
        while n > 0 && d > 0 {
            n /= 10;
            d /= 10;
        }
        n > d
    }
}

fn main() {
    let mut count = 0u32;
    let mut frac = Fraction::new();
    while {
        if frac.has_numerator_more_digits() {
            count += 1;
        }
        frac.increment();
        frac.n <= 1000
    } {}

    println!("{}", count);
    assert_eq!(count, 153);
}

fn main() {
    let r1 = 1f64 + 2f64.sqrt();
    let r2 = 1f64 - 2f64.sqrt();
    let deno_c = 1.5f64 * 2f64.log10();
    let nume_c = 2f64.log10();
    let log10_r1 = r1.log10();
    let r2_over_r1 = r2 / r1;

    let mut count = 0u32;
    let mut pow = r2_over_r1.clone();
    for n in 2u32..=1001 {
        pow *= r2_over_r1;
        let nlog10r1 = n as f64 * log10_r1;
        let deno_digit = (nlog10r1 + (1f64 - pow).log10() - deno_c) as u32;
        let nume_digit = (nlog10r1 + (1f64 + pow).log10() - nume_c) as u32;
        if nume_digit > deno_digit {
            count += 1;
        }
    }

    println!("{}", count);
    assert_eq!(count, 153);
}
fn main() {
    let r1 = 1f64 + 2f64.sqrt();
    let deno_c = 1.5f64 * 2f64.log10();
    let nume_c = 2f64.log10();
    let log10_r1 = r1.log10();

    let mut count = 0u32;
    for n in 2u32..=1001 {
        let nlog10r1 = n as f64 * log10_r1;
        let deno_digit = (nlog10r1 - deno_c) as u32;
        let nume_digit = (nlog10r1 - nume_c) as u32;
        if nume_digit > deno_digit {
            count += 1;
        }
    }

    println!("{}", count);
    assert_eq!(count, 153);
}
Problem 58 "Spiral primes"

Starting with 1 and spiralling anticlockwise in the following way, a square spiral with side length 7 is formed.

37 36 35 34 33 32 31 38 17 16 15 14 13 30 39 18 5 4 3 12 29 40 19 6 1 2 11 28 41 20 7 8 9 10 27 42 21 22 23 24 25 26 43 44 45 46 47 48 49

It is interesting to note that the odd squares lie along the bottom right diagonal, but what is more interesting is that 8 out of the 13 numbers lying along both diagonals are prime; that is, a ratio of 8/13 ≈ 62%.

If one complete new layer is wrapped around the spiral above, a square spiral with side length 9 will be formed. If this process is continued, what is the side length of the square spiral for which the ratio of primes along both diagonals first falls below 10%?

問 58 「螺旋素数」

面白いことに, 奇平方数が右下の対角線上に出現する. もっと面白いことには, 対角線上の13個の数字のうち, 8個が素数である. ここで割合は8/13 ≈ 62%である.

渦巻きに新しい層を付け加えよう. すると辺の長さが9の渦巻きが出来る. 以下, この操作を繰り返していく. 対角線上の素数の割合が10%未満に落ちる最初の辺の長さを求めよ.

fn is_prime(n: u32) -> bool {
    if n < 2 {
        return false;
    }
    if n == 2 || n == 3 || n == 5 {
        return true;
    }
    for d in &[2, 3, 5] {
        if n % *d == 0 {
            return false;
        }
    }
    let side = (n as f32).sqrt() as u32;
    let mut d = 5;
    for &i in [2, 4].iter().cycle() {
        d += i;
        if d > side {
            break;
        }
        if n % d == 0 {
            return false;
        }
    }
    true
}

struct Spiral {
    n: u32,
    diagonal_area: u32,
    primes: u32,
}

impl Spiral {
    fn increment(&mut self) {
        self.n += 1;
        self.diagonal_area += 4;
        self.primes += self.prime_corners();
    }
    fn prime_corners(&self) -> u32 {
        let square = (2 * self.n + 1) * (2 * self.n + 1);
        (1u32..=3)
            .map(|i| square - 2 * self.n * i)
            .filter(|&n| is_prime(n))
            .count() as u32
    }
}

fn main() {
   let mut spiral = Spiral {
        n: 0,
        diagonal_area: 1,
        primes: 0,
    };
    while {
        spiral.increment();
        spiral.primes * 10 >= spiral.diagonal_area
    } {}
    let side = 2 * spiral.n + 1;

    println!("{}", side);
    assert_eq!(side, 26241)
}

The LCG is still good enough for simple tasks like Miller-Rabin primality test, or FreeCell deals. (Linear congruential generator, rosettacode.org)

use std::time::{SystemTime, UNIX_EPOCH};

mod index {
    pub struct Index {
        pub i: usize,
        f: u8,
    }

    impl Index {
        pub fn increment(&mut self) {
            self.i += 2 << self.f;
            self.f ^= 1;
        }
        pub fn new() -> Self {
            Self { i: 5, f: 0 }
        }
    }
}

mod sieve {
    pub struct Sieve {
        sieve: [bool; 100_001],
        index: super::index::Index,
    }

    impl Sieve {
        pub fn new() -> Self {
            let mut s = Self {
                sieve: [true; 100_001],
                index: super::index::Index::new(),
            };
            s.init();
            s
        }
        pub fn sieve_len(&self) -> u32 {
            self.sieve.len() as u32
        }
        fn init(&mut self) {
            let side = ((self.sieve.len() - 1) as f32).sqrt() as usize;
            while self.index.i <= side {
                if self.sieve[self.index.i] {
                    let p = self.index.i;
                    (p * p..self.sieve.len())
                        .step_by(p)
                        .for_each(|i| self.sieve[i] = false);
                }
                self.index.increment();
            }
        }
        pub fn is_prime(&self, n: u32) -> bool {
            assert!(n < self.sieve.len() as u32);
            if n < 2 {
                return false;
            }
            if n % 2 == 0 {
                return n == 2;
            }
            if n % 3 == 0 {
                return n == 3;
            }
            return self.sieve[n as usize];
        }
    }
}

mod rand {
    pub struct MinStdRand {
        state: u64,
    }

    impl MinStdRand {
        const M: u64 = 2147483647;
        const A: u64 = 48271;
        const MAX: u64 = 2147483646;
        pub fn new(seed: u32) -> Self {
            Self { state: seed as u64 }
        }
        pub fn next(&mut self, partition: u32) -> u32 {
            let p = partition as u64;
            assert!(p > 0 && p <= Self::MAX);
            self.state = Self::A * self.state % Self::M;
            loop {
                let n = self.state * p / Self::MAX;
                if n < p {
                    return n as u32;
                }
            }
        }
    }
}

fn mod_pow(a: u32, exp: u32, m: u32) -> u32 {
    let (mut a, mut exp, m) = (a as u64, exp as u64, m as u64);
    if m == 1 {
        return 0;
    }
    if exp == 0 {
        return 1;
    }
    let mut result = 1;
    a %= m;
    loop {
        if exp % 2 == 1 {
            result = result * a % m;
        }
        exp >>= 1;
        if exp == 0 {
            break;
        }
        a = a * a % m;
    }
    result as u32
}

/// finds the k*2^e form of given n 
fn coefficient_and_exponent_of_two(mut n: u32) -> (u32, u32) {
    let mut exp = 0u32;
    while n % 2 == 0 {
        n /= 2;
        exp += 1;
    }
    (n, exp)
}

fn is_probable_prime(n: u32, rand: &mut rand::MinStdRand) -> bool {
    if n == 1 {
        return false;
    }
    if n % 2 == 0 {
        return n == 2;
    }
    let (d, s) = coefficient_and_exponent_of_two(n - 1); 
    'next_trial: for _ in 0..3 {
        // 2 <= a < n
        let a = 2 + rand.next(n - 2);
        let mut x = mod_pow(a, d, n);
        if x == 1 || x == n - 1 {
            continue 'next_trial;
        }
        for _ in 1..s {
            x = (x as u64 * x as u64 % n as u64) as u32;
            if x == n - 1 {
                continue 'next_trial;
            }
        }
        return false;
    }
    true
}

struct Spiral {
    n: u32,
    diagonal_area: u32,
    primes: u32,
    sieve: sieve::Sieve,
    rand: rand::MinStdRand,
}

impl Spiral {
    fn increment(&mut self) {
        self.n += 1;
        self.diagonal_area += 4;
        self.primes += self.prime_corners();
    }
    fn prime_corners(&mut self) -> u32 {
        let square = (2 * self.n + 1) * (2 * self.n + 1);
        let n = self.n.clone();
        (1u32..=3)
            .map(|i| square - 2 * n * i)
            .filter(|&n| {
                if n < self.sieve.sieve_len() {
                    self.sieve.is_prime(n)
                } else {
                    is_probable_prime(n, &mut self.rand)
                }
            })
            .count() as u32
    }
}

fn main() {
    let seed = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .subsec_nanos();
    let mut spiral = Spiral {
        n: 0,
        diagonal_area: 1,
        primes: 0,
        sieve: sieve::Sieve::new(),
        rand: rand::MinStdRand::new(seed),
    };
    while {
        spiral.increment();
        spiral.primes * 10 >= spiral.diagonal_area
    } {}
    let side = 2 * spiral.n + 1;

    println!("{}", side);
    assert_eq!(side, 26241)
}
Problem 59 "XOR decryption"

Each character on a computer is assigned a unique code and the preferred standard is ASCII (American Standard Code for Information Interchange). For example, uppercase A = 65, asterisk (*) = 42, and lowercase k = 107.

A modern encryption method is to take a text file, convert the bytes to ASCII, then XOR each byte with a given value, taken from a secret key. The advantage with the XOR function is that using the same encryption key on the cipher text, restores the plain text; for example, 65 XOR 42 = 107, then 107 XOR 42 = 65.

For unbreakable encryption, the key is the same length as the plain text message, and the key is made up of random bytes. The user would keep the encrypted message and the encryption key in different locations, and without both "halves", it is impossible to decrypt the message.

Unfortunately, this method is impractical for most users, so the modified method is to use a password as a key. If the password is shorter than the message, which is likely, the key is repeated cyclically throughout the message. The balance for this method is using a sufficiently long password key for security, but short enough to be memorable.

Your task has been made easy, as the encryption key consists of three lower case characters. Using p059_cipher.txt, a file containing the encrypted ASCII codes, and the knowledge that the plain text must contain common English words, decrypt the message and find the sum of the ASCII values in the original text.

問 59 「XOR暗号解読」

各文字はそれぞれ一意のコードに割り当てられている. よく使われる標準としてASCII (American Standard Code for Information Interchange) がある. ASCIIでは, 大文字A = 65, アスタリスク (*) = 42, 小文字k = 107というふうに割り当てられている.

モダンな暗号化の方法として, テキストファイルの各バイトをASCIIに変換し, 秘密鍵から計算された値とXORを取るという手法がある. XOR関数の良い点は, 暗号化に用いたのと同じ暗号化鍵でXORを取ると平文を復号できる点である. 65 XOR 42 = 107であり, 107 XOR 42 = 65である.

破られない暗号化のためには, 鍵は平文と同じ長さのランダムなバイト列でなければならない. ユーザーは暗号文と暗号化鍵を別々の場所に保存する必要がある. また, もし一方が失われると, 暗号文を復号することは不可能になる.

悲しいかな, この手法はほとんどのユーザーにとって非現実的である. そこで, 鍵の変わりにパスワードを用いる手法が用いられる. パスワードが平文より短ければ (よくあることだが), パスワードは鍵として繰り返し用いられる. この手法では, 安全性を保つために十分長いパスワードを用いる必要があるが, 記憶するためにはある程度短くないといけない.

この問題での課題は簡単になっている. 暗号化鍵は3文字の小文字である. cipher1.txtは暗号化されたASCIIのコードを含んでいる. また, 平文はよく用いられる英単語を含んでいる. この暗号文を復号し, 平文のASCIIでの値の和を求めよ.

fn get_most_frequent_value(position: usize) -> u8 {
    let mut freq = [0u8; 256];
    for i in (position..).step_by(3) {
        if i > ENC.len() - 1 {
            break;
        }
        freq[ENC[i] as usize] += 1;
    }
    freq.iter()
        .enumerate()
        .reduce(|a, b| if a.1 > b.1 { a } else { b })
        .map(|(i, _)| i as u8)
        .expect("freq array's length must be > 0.")
}

fn get_key_from_space(enc: u8) -> u8 {
    let space = ' ' as u8;
    for c in 'a'..='z' {
        if c as u8 ^ enc == space {
            return c as u8;
        }
    }
    unreachable!();
}

fn decrypt(dec: &mut [u8], position: usize, key: u8) {
    for i in (position..).step_by(3) {
        if i > ENC.len() - 1 {
            break;
        }
        dec[i] = ENC[i] ^ key;
    }
}

fn main() {
    let mut dec = vec![0; ENC.len()];
    for i in 0usize..3 {
        let enc = get_most_frequent_value(i);
        let key = get_key_from_space(enc);
        decrypt(&mut dec, i, key);
    }
    let ans = dec.iter().map(|&v| v as u32).sum::<u32>();
    println!("{}", ans);
    assert_eq!(ans, 129448);
    println!("{}", String::from_utf8(dec).unwrap());
}

const ENC: [u8; 1455] = [
    36, 22, 80, 0, 0, 4, 23, 25, 19, 17, 88, 4, 4, 19, 21, 11, 88, 22, 23, 23, 29, 69, 12, 24, 0,
    88, 25, 11, 12, 2, 10, 28, 5, 6, 12, 25, 10, 22, 80, 10, 30, 80, 10, 22, 21, 69, 23, 22, 69,
    61, 5, 9, 29, 2, 66, 11, 80, 8, 23, 3, 17, 88, 19, 0, 20, 21, 7, 10, 17, 17, 29, 20, 69, 8, 17,
    21, 29, 2, 22, 84, 80, 71, 60, 21, 69, 11, 5, 8, 21, 25, 22, 88, 3, 0, 10, 25, 0, 10, 5, 8, 88,
    2, 0, 27, 25, 21, 10, 31, 6, 25, 2, 16, 21, 82, 69, 35, 63, 11, 88, 4, 13, 29, 80, 22, 13, 29,
    22, 88, 31, 3, 88, 3, 0, 10, 25, 0, 11, 80, 10, 30, 80, 23, 29, 19, 12, 8, 2, 10, 27, 17, 9,
    11, 45, 95, 88, 57, 69, 16, 17, 19, 29, 80, 23, 29, 19, 0, 22, 4, 9, 1, 80, 3, 23, 5, 11, 28,
    92, 69, 9, 5, 12, 12, 21, 69, 13, 30, 0, 0, 0, 0, 27, 4, 0, 28, 28, 28, 84, 80, 4, 22, 80, 0,
    20, 21, 2, 25, 30, 17, 88, 21, 29, 8, 2, 0, 11, 3, 12, 23, 30, 69, 30, 31, 23, 88, 4, 13, 29,
    80, 0, 22, 4, 12, 10, 21, 69, 11, 5, 8, 88, 31, 3, 88, 4, 13, 17, 3, 69, 11, 21, 23, 17, 21,
    22, 88, 65, 69, 83, 80, 84, 87, 68, 69, 83, 80, 84, 87, 73, 69, 83, 80, 84, 87, 65, 83, 88, 91,
    69, 29, 4, 6, 86, 92, 69, 15, 24, 12, 27, 24, 69, 28, 21, 21, 29, 30, 1, 11, 80, 10, 22, 80,
    17, 16, 21, 69, 9, 5, 4, 28, 2, 4, 12, 5, 23, 29, 80, 10, 30, 80, 17, 16, 21, 69, 27, 25, 23,
    27, 28, 0, 84, 80, 22, 23, 80, 17, 16, 17, 17, 88, 25, 3, 88, 4, 13, 29, 80, 17, 10, 5, 0, 88,
    3, 16, 21, 80, 10, 30, 80, 17, 16, 25, 22, 88, 3, 0, 10, 25, 0, 11, 80, 12, 11, 80, 10, 26, 4,
    4, 17, 30, 0, 28, 92, 69, 30, 2, 10, 21, 80, 12, 12, 80, 4, 12, 80, 10, 22, 19, 0, 88, 4, 13,
    29, 80, 20, 13, 17, 1, 10, 17, 17, 13, 2, 0, 88, 31, 3, 88, 4, 13, 29, 80, 6, 17, 2, 6, 20, 21,
    69, 30, 31, 9, 20, 31, 18, 11, 94, 69, 54, 17, 8, 29, 28, 28, 84, 80, 44, 88, 24, 4, 14, 21,
    69, 30, 31, 16, 22, 20, 69, 12, 24, 4, 12, 80, 17, 16, 21, 69, 11, 5, 8, 88, 31, 3, 88, 4, 13,
    17, 3, 69, 11, 21, 23, 17, 21, 22, 88, 25, 22, 88, 17, 69, 11, 25, 29, 12, 24, 69, 8, 17, 23,
    12, 80, 10, 30, 80, 17, 16, 21, 69, 11, 1, 16, 25, 2, 0, 88, 31, 3, 88, 4, 13, 29, 80, 21, 29,
    2, 12, 21, 21, 17, 29, 2, 69, 23, 22, 69, 12, 24, 0, 88, 19, 12, 10, 19, 9, 29, 80, 18, 16, 31,
    22, 29, 80, 1, 17, 17, 8, 29, 4, 0, 10, 80, 12, 11, 80, 84, 67, 80, 10, 10, 80, 7, 1, 80, 21,
    13, 4, 17, 17, 30, 2, 88, 4, 13, 29, 80, 22, 13, 29, 69, 23, 22, 69, 12, 24, 12, 11, 80, 22,
    29, 2, 12, 29, 3, 69, 29, 1, 16, 25, 28, 69, 12, 31, 69, 11, 92, 69, 17, 4, 69, 16, 17, 22, 88,
    4, 13, 29, 80, 23, 25, 4, 12, 23, 80, 22, 9, 2, 17, 80, 70, 76, 88, 29, 16, 20, 4, 12, 8, 28,
    12, 29, 20, 69, 26, 9, 69, 11, 80, 17, 23, 80, 84, 88, 31, 3, 88, 4, 13, 29, 80, 21, 29, 2, 12,
    21, 21, 17, 29, 2, 69, 12, 31, 69, 12, 24, 0, 88, 20, 12, 25, 29, 0, 12, 21, 23, 86, 80, 44,
    88, 7, 12, 20, 28, 69, 11, 31, 10, 22, 80, 22, 16, 31, 18, 88, 4, 13, 25, 4, 69, 12, 24, 0, 88,
    3, 16, 21, 80, 10, 30, 80, 17, 16, 25, 22, 88, 3, 0, 10, 25, 0, 11, 80, 17, 23, 80, 7, 29, 80,
    4, 8, 0, 23, 23, 8, 12, 21, 17, 17, 29, 28, 28, 88, 65, 75, 78, 68, 81, 65, 67, 81, 72, 70, 83,
    64, 68, 87, 74, 70, 81, 75, 70, 81, 67, 80, 4, 22, 20, 69, 30, 2, 10, 21, 80, 8, 13, 28, 17,
    17, 0, 9, 1, 25, 11, 31, 80, 17, 16, 25, 22, 88, 30, 16, 21, 18, 0, 10, 80, 7, 1, 80, 22, 17,
    8, 73, 88, 17, 11, 28, 80, 17, 16, 21, 11, 88, 4, 4, 19, 25, 11, 31, 80, 17, 16, 21, 69, 11, 1,
    16, 25, 2, 0, 88, 2, 10, 23, 4, 73, 88, 4, 13, 29, 80, 11, 13, 29, 7, 29, 2, 69, 75, 94, 84,
    76, 65, 80, 65, 66, 83, 77, 67, 80, 64, 73, 82, 65, 67, 87, 75, 72, 69, 17, 3, 69, 17, 30, 1,
    29, 21, 1, 88, 0, 23, 23, 20, 16, 27, 21, 1, 84, 80, 18, 16, 25, 6, 16, 80, 0, 0, 0, 23, 29, 3,
    22, 29, 3, 69, 12, 24, 0, 88, 0, 0, 10, 25, 8, 29, 4, 0, 10, 80, 10, 30, 80, 4, 88, 19, 12, 10,
    19, 9, 29, 80, 18, 16, 31, 22, 29, 80, 1, 17, 17, 8, 29, 4, 0, 10, 80, 12, 11, 80, 84, 86, 80,
    35, 23, 28, 9, 23, 7, 12, 22, 23, 69, 25, 23, 4, 17, 30, 69, 12, 24, 0, 88, 3, 4, 21, 21, 69,
    11, 4, 0, 8, 3, 69, 26, 9, 69, 15, 24, 12, 27, 24, 69, 49, 80, 13, 25, 20, 69, 25, 2, 23, 17,
    6, 0, 28, 80, 4, 12, 80, 17, 16, 25, 22, 88, 3, 16, 21, 92, 69, 49, 80, 13, 25, 6, 0, 88, 20,
    12, 11, 19, 10, 14, 21, 23, 29, 20, 69, 12, 24, 4, 12, 80, 17, 16, 21, 69, 11, 5, 8, 88, 31, 3,
    88, 4, 13, 29, 80, 22, 29, 2, 12, 29, 3, 69, 73, 80, 78, 88, 65, 74, 73, 70, 69, 83, 80, 84,
    87, 72, 84, 88, 91, 69, 73, 95, 87, 77, 70, 69, 83, 80, 84, 87, 70, 87, 77, 80, 78, 88, 21, 17,
    27, 94, 69, 25, 28, 22, 23, 80, 1, 29, 0, 0, 22, 20, 22, 88, 31, 11, 88, 4, 13, 29, 80, 20, 13,
    17, 1, 10, 17, 17, 13, 2, 0, 88, 31, 3, 88, 4, 13, 29, 80, 6, 17, 2, 6, 20, 21, 75, 88, 62, 4,
    21, 21, 9, 1, 92, 69, 12, 24, 0, 88, 3, 16, 21, 80, 10, 30, 80, 17, 16, 25, 22, 88, 29, 16, 20,
    4, 12, 8, 28, 12, 29, 20, 69, 26, 9, 69, 65, 64, 69, 31, 25, 19, 29, 3, 69, 12, 24, 0, 88, 18,
    12, 9, 5, 4, 28, 2, 4, 12, 21, 69, 80, 22, 10, 13, 2, 17, 16, 80, 21, 23, 7, 0, 10, 89, 69, 23,
    22, 69, 12, 24, 0, 88, 19, 12, 10, 19, 16, 21, 22, 0, 10, 21, 11, 27, 21, 69, 23, 22, 69, 12,
    24, 0, 88, 0, 0, 10, 25, 8, 29, 4, 0, 10, 80, 10, 30, 80, 4, 88, 19, 12, 10, 19, 9, 29, 80, 18,
    16, 31, 22, 29, 80, 1, 17, 17, 8, 29, 4, 0, 10, 80, 12, 11, 80, 84, 86, 80, 36, 22, 20, 69, 26,
    9, 69, 11, 25, 8, 17, 28, 4, 10, 80, 23, 29, 17, 22, 23, 30, 12, 22, 23, 69, 49, 80, 13, 25, 6,
    0, 88, 28, 12, 19, 21, 18, 17, 3, 0, 88, 18, 0, 29, 30, 69, 25, 18, 9, 29, 80, 17, 23, 80, 1,
    29, 4, 0, 10, 29, 12, 22, 21, 69, 12, 24, 0, 88, 3, 16, 21, 3, 69, 23, 22, 69, 12, 24, 0, 88,
    3, 16, 26, 3, 0, 9, 5, 0, 22, 4, 69, 11, 21, 23, 17, 21, 22, 88, 25, 11, 88, 7, 13, 17, 19, 13,
    88, 4, 13, 29, 80, 0, 0, 0, 10, 22, 21, 11, 12, 3, 69, 25, 2, 0, 88, 21, 19, 29, 30, 69, 22, 5,
    8, 26, 21, 23, 11, 94,
];
Problem 60 "Prime pair sets"

The primes 3, 7, 109, and 673, are quite remarkable. By taking any two primes and concatenating them in any order the result will always be prime. For example, taking 7 and 109, both 7109 and 1097 are prime. The sum of these four primes, 792, represents the lowest sum for a set of four primes with this property.

Find the lowest sum for a set of five primes for which any two primes concatenate to produce another prime.

問 60 「素数ペア集合」

素数3, 7, 109, 673は非凡な性質を持っている. 任意の2つの素数を任意の順で繋げると, また素数になっている. 例えば, 7と109を用いると, 7109と1097の両方が素数である. これら4つの素数の和は792である. これは, このような性質をもつ4つの素数の集合の和の中で最小である.

任意の2つの素数を繋げたときに別の素数が生成される, 5つの素数の集合の和の中で最小のものを求めよ.

Primes

Recursion

use std::time::{SystemTime, UNIX_EPOCH};
use std::collections::HashMap;

fn concat(mut a: u32, b: u32) -> u32 {
    let mut t = b.clone();
    while t > 0 {
        a *= 10;
        t /= 10;
    }
    a + b
}

fn is_pair(a: u32, b: u32, sieve: &sieve::Sieve, rand: &mut rand::MinStdRand) -> bool {
    let ab = concat(a, b);
    let is_ab_prime = if ab < sieve.sieve_len() {
        sieve.is_prime(ab)
    } else {
        is_probable_prime(ab, rand)
    };
    if !is_ab_prime {
        return false;
    }
    let ba = concat(b, a);
    if ba < sieve.sieve_len() {
        sieve.is_prime(ba)
    } else {
        is_probable_prime(ba, rand)
    }
}

fn pairing(
    a: u32,
    primes: &[u32],
    sieve: &sieve::Sieve,
    rand: &mut rand::MinStdRand,
) -> Option<Vec<u32>> {
    let mut pairs: Option<Vec<u32>> = None;
    for &b in primes {
        if !is_pair(a, b, sieve, rand) {
            continue;
        }
        if let Some(vec) = pairs.as_mut() {
            vec.push(b);
        } else {
            pairs.insert(vec![b]);
        }
    }
    pairs
}

fn dig_to_bottom(
    candidates: &[u32],
    pair_table: &HashMap<u32, Vec<u32>>,
    drain: &[u32],
    angle: usize,
) -> Result<Vec<u32>, ()> {
    if angle == 1 {
        let set = std::iter::once(candidates.get(0).unwrap())
            .chain(drain.iter())
            .map(|&n| n)
            .collect::<Vec<u32>>();
        return Ok(set);
    }
    for p in candidates.iter() {
        let pairs = pair_table.get(p);
        let pairs = if pairs.is_none() {
            continue;
        } else {
            pairs.unwrap()
        };
        if pairs.len() < angle - 1 {
            continue;
        }
        let pairs = pairs
            .iter()
            .filter(|&e| candidates.binary_search(e).is_ok())
            .map(|e| *e)
            .collect::<Vec<u32>>();
        if pairs.len() < angle - 1 {
            continue;
        }
        let drain = std::iter::once(p)
            .chain(drain.iter())
            .map(|&n| n)
            .collect::<Vec<u32>>();
        let result = dig_to_bottom(&pairs, pair_table, &drain, angle - 1);
        if result.is_ok() {
            return result;
        }
    }
    Err(())
}

fn mod_pow(a: u32, exp: u32, m: u32) -> u32 {
    let (mut a, mut exp, m) = (a as u64, exp as u64, m as u64);
    if m == 1 {
        return 0;
    }
    if exp == 0 {
        return 1;
    }
    let mut result = 1;
    a %= m;
    loop {
        if exp % 2 == 1 {
            result = result * a % m;
        }
        exp >>= 1;
        if exp == 0 {
            break;
        }
        a = a * a % m;
    }
    result as u32
}

/// finds the k*2^e form of given n
fn coefficient_and_exponent_of_two(mut n: u32) -> (u32, u32) {
    let mut exp = 0u32;
    while n % 2 == 0 {
        n /= 2;
        exp += 1;
    }
    (n, exp)
}

fn is_probable_prime(n: u32, rand: &mut rand::MinStdRand) -> bool {
    if n == 1 {
        return false;
    }
    if n % 2 == 0 {
        return n == 2;
    }
    let (d, s) = coefficient_and_exponent_of_two(n - 1);
    'next_trial: for _ in 0..3 {
        let a = 2 + rand.next(n - 2);
        let mut x = mod_pow(a, d, n);
        if x == 1 || x == n - 1 {
            continue 'next_trial;
        }
        for _ in 1..s {
            x = (x as u64 * x as u64 % n as u64) as u32;
            if x == n - 1 {
                continue 'next_trial;
            }
        }
        return false;
    }
    true
}

mod index {
    pub struct Index {
        pub i: usize,
        f: u8,
    }

    impl Index {
        pub fn increment(&mut self) {
            self.i += 2 << self.f;
            self.f ^= 1;
        }
        pub fn new() -> Self {
            Self { i: 5, f: 0 }
        }
    }
}

mod sieve {
    pub struct Sieve {
        sieve: Vec<bool>,
        index: super::index::Index,
        primes: Vec<usize>,
        queue_cursor: usize,
    }

    impl Sieve {
        pub fn new(below: u32) -> Self {
            assert!(below > 4);
            let sieve = vec![true; below as usize];
            let mut s = Self {
                sieve: sieve,
                index: super::index::Index::new(),
                primes: vec![],
                queue_cursor: 0,
            };
            s.clean_sieve();
            s
        }
        pub fn sieve_len(&self) -> u32 {
            self.sieve.len() as u32
        }
        fn rule_out(&mut self, prime: usize) {
            for i in (prime * prime..self.sieve.len()).step_by(prime) {
                self.sieve[i] = false;
            }
        }
        fn rule_out_from_previous_position(&mut self, prime: usize, pp: usize) {
            use std::cmp::max;
            let begin = max((((pp - 1) / prime) + 1) * prime, prime * prime);
            for i in (begin..self.sieve.len()).step_by(prime) {
                self.sieve[i] = false;
            }
        }
        fn clean_sieve(&mut self) {
            let side = ((self.sieve.len() - 1) as f32).sqrt() as usize;
            while self.index.i <= side {
                if self.sieve[self.index.i] {
                    self.primes.push(self.index.i);
                    self.rule_out(self.index.i);
                }
                self.index.increment();
            }
            while self.index.i < self.sieve.len() {
                if self.sieve[self.index.i] {
                    self.primes.push(self.index.i);
                }
                self.index.increment();
            }
        }
        fn extend(&mut self) {
            let previous_len = self.sieve.len();
            self.sieve.extend(vec![true; previous_len]);
            for &p in &self.primes.clone() {
                self.rule_out_from_previous_position(p, previous_len);
            }
            self.clean_sieve();
        }
        pub fn next_prime(&mut self) -> u32 {
            loop {
                if self.queue_cursor == 0 {
                    self.queue_cursor += 1;
                    return 2;
                }
                if self.queue_cursor == 1 {
                    self.queue_cursor += 1;
                    return 3;
                }
                if self.queue_cursor - 2 < self.primes.len() {
                    self.queue_cursor += 1;
                    return self.primes[self.queue_cursor - 3] as u32;
                }
                self.extend();
            }
        }
        pub fn is_prime(&self, n: u32) -> bool {
            assert!(n < self.sieve.len() as u32);
            if n < 2 {
                return false;
            }
            if n % 2 == 0 {
                return n == 2;
            }
            if n % 3 == 0 {
                return n == 3;
            }
            return self.sieve[n as usize];
        }
    }
}

mod rand {
    pub struct MinStdRand {
        state: u64,
    }

    impl MinStdRand {
        const M: u64 = 2147483647;
        const A: u64 = 48271;
        const MAX: u64 = 2147483646;
        pub fn new(seed: u32) -> Self {
            Self { state: seed as u64 }
        }
        pub fn next(&mut self, partition: u32) -> u32 {
            let p = partition as u64;
            assert!(p > 0 && p <= Self::MAX);
            self.state = Self::A * self.state % Self::M;
            loop {
                let n = self.state * p / Self::MAX;
                if n < p {
                    return n as u32;
                }
            }
        }
    }
}

fn prime_graph(angle: usize) -> Vec<u32> {
    let mut primes = vec![];
    let mut sieve = sieve::Sieve::new(1000);
    let seed = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .subsec_nanos();
    let mut rand = rand::MinStdRand::new(seed);
    let mut pair_table: HashMap<u32, Vec<u32>> = HashMap::new();
    sieve.next_prime(); // discard 2
    loop {
        let p = sieve.next_prime();
        let pairs = pairing(p, &primes, &sieve, &mut rand);
        primes.push(p);
        let pairs = if pairs.is_none() {
            continue;
        } else {
            pairs.unwrap()
        };
        if pairs.len() < angle - 1 {
            pair_table.insert(p, pairs);
            continue;
        }
        if let Ok(ans) = dig_to_bottom(&pairs, &pair_table, &vec![p], angle - 1) {
            break ans;
        }
        pair_table.insert(p, pairs);
    }
} 

fn main() {
    {
        let ans = prime_graph(3);
        let sum = ans.iter().sum::<u32>();
        println!("{} {:?}", sum, ans);
        assert_eq!(sum, 107);
    }
    {
        let ans = prime_graph(4);
        let sum = ans.iter().sum::<u32>();
        println!("{} {:?}", sum, ans);
        assert_eq!(sum, 792);
    }
    {
        let ans = prime_graph(5);
        let sum = ans.iter().sum::<u32>();
        println!("{} {:?}", sum, ans);
        assert_eq!(sum, 26033);
    }
}
Problem 61 "Cyclical figurate numbers"

Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:

Triangle P3,n=n(n+1)/2 1, 3, 6, 10, 15, ...
Square P4,n=n2 1, 4, 9, 16, 25, ...
Pentagonal P5,n=n(3n−1)/2 1, 5, 12, 22, 35, ...
Hexagonal P6,n=n(2n−1) 1, 6, 15, 28, 45, ...
Heptagonal P7,n=n(5n−3)/2 1, 7, 18, 34, 55, ...
Octagonal P8,n=n(3n−2) 1, 8, 21, 40, 65, ...

The ordered set of three 4-digit numbers: 8128, 2882, 8281, has three interesting properties.

  1. The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).
  2. Each polygonal type: triangle (P3,127=8128), square (P4,91=8281), and pentagonal (P5,44=2882), is represented by a different number in the set.
  3. This is the only set of 4-digit numbers with this property.

Find the sum of the only ordered set of six cyclic 4-digit numbers for which each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and octagonal, is represented by a different number in the set.

問 61 「巡回図形数」

三角数, 四角数, 五角数, 六角数, 七角数, 八角数は多角数であり, それぞれ以下の式で生成される.

3つの4桁の数の順番付きの集合 (8128, 2882, 8281) は以下の面白い性質を持つ.

  • この集合は巡回的である. 最後の数も含めて, 各数の後半2桁は次の数の前半2桁と一致する
  • それぞれ多角数である: 三角数 (P3,127=8128), 四角数 (P4,91=8281), 五角数 (P5,44=2882) がそれぞれ別の数字で集合に含まれている
  • 4桁の数の組で上の2つの性質をもつはこの組だけである.

三角数, 四角数, 五角数, 六角数, 七角数, 八角数が全て表れる6つの巡回する4桁の数からなる唯一の順序集合の和を求めよ.

#[derive(Debug)]
struct PolyNum {
    left: u8,
    right: u8,
    side_ident: u8,
}

fn next(filter: u8, polynums: &[PolyNum], chain: &[&PolyNum]) -> Option<u32> {
    if filter == 0b11111100 {
        if chain[chain.len() - 1].right != chain[0].left {
            return None;
        }
        println!("{:#?}", chain);
        let sum = chain
            .iter()
            .map(|&pn| pn.left as u32 * 100 + pn.right as u32)
            .sum();
        return Some(sum);
    }
    let oks = polynums
        .iter()
        .filter(|&pn| pn.left == chain[chain.len() - 1].right)
        .filter(|&pn| pn.side_ident & filter == 0)
        .collect::<Vec<&PolyNum>>();
    for pn in oks {
        let chain = chain
            .iter()
            .map(|&p| p)
            .chain(std::iter::once(pn))
            .collect::<Vec<&PolyNum>>();
        let child = next(filter | pn.side_ident, polynums, &chain);
        if child.is_some() {
            return child;
        }
    }
    None
}

fn generate_four_digit_polygonal_numbers(side: u32) -> Vec<PolyNum> {
    let polygonal_number_genenerator_builder =
        |side: u32| move |n: u32| (side - 2) * n * (n - 1) / 2 + n;

    let gen = polygonal_number_genenerator_builder(side);
    let mut polynums = vec![];
    for n in 1u32.. {
        let x = gen(n);
        if x > 9999 {
            break;
        }
        if x < 1000 {
            continue;
        }
        polynums.push(PolyNum {
            left: (x / 100) as u8,
            right: (x % 100) as u8,
            side_ident: 1 << (side - 1),
        });
    }
    polynums
}

fn cyclical_figurate_numbers() -> u32 {
    let octs = generate_four_digit_polygonal_numbers(8);

    let mut polynums = vec![];
    for s in 3u32..=7 {
        polynums.extend(generate_four_digit_polygonal_numbers(s).into_iter());
    }

    for oct in &octs {
        if let Some(sum) = next(oct.side_ident, &polynums, &vec![oct]) {
            return sum;
        }
    }
    unreachable!();
}

fn main() {
   let ans = cyclical_figurate_numbers();
   println!("{}", ans);
   assert_eq!(ans, 28684);
}
Problem 62 "Cubic permutations"

The cube, 41063625 (3453), can be permuted to produce two other cubes: 56623104 (3843) and 66430125 (4053). In fact, 41063625 is the smallest cube which has exactly three permutations of its digits which are also cube.

Find the smallest cube for which exactly five permutations of its digits are cube.

問 62 「立方数置換」

立方数 41063625 (3453) は, 桁の順番を入れ替えると2つの立方数になる: 56623104 (3843) と 66430125 (4053) である. 41063625は, 立方数になるような桁の置換をちょうど3つもつ最小の立方数である.

立方数になるような桁の置換をちょうど5つもつ最小の立方数を求めよ.

use std::collections::HashMap;

fn freq(mut n: u64) -> u64 {
    let mut freq = 0u64;
    while n > 0 {
        freq += 0b000001 << ((n % 10) * 6);
        n /= 10;
    }
    freq
}

fn min(counts: &HashMap<u64, (u8, u16)>, count: u8) -> Option<&u16> {
    counts
        .iter()
        .filter(|(_, (c, _))| *c == count)
        .map(|(_, (_, n))| n)
        .min()
}

fn cubic_permutations(permutation: u8) -> u64 {
    assert!(permutation > 2);
    let mut counts: HashMap<u64, (u8, u16)> = HashMap::new();
    let mut digits = 1u64;
    while digits < 100u64.pow(3) {
        digits *= 10;
    }
    for n in 100u16.. {
        let cube = (n as u64).pow(3);
        if digits as f32 / cube as f32 <= 1f32 {
            if let Some(&n) = min(&counts, permutation) {
                return (n as u64).pow(3);
            }
            counts.clear();
            digits *= 10;
        }
        let freq = freq(cube);
        if let Some((cnt, _)) = counts.get_mut(&freq) {
            *cnt += 1;
            continue;
        }
        counts.insert(freq, (1, n));
    }
    unreachable!();
}

fn main() {
    {
        let ans = cubic_permutations(3);
        println!("{}", ans);
        assert_eq!(ans, 41063625);
    }
    {
        let ans = cubic_permutations(4);
        println!("{}", ans);
        assert_eq!(ans, 1006012008);
    }
    {
        let ans = cubic_permutations(5);
        println!("{}", ans);
        assert_eq!(ans, 127035954683);
    }
    {
        let ans = cubic_permutations(6);
        println!("{}", ans);
        assert_eq!(ans, 1000600120008);
    }
}
Problem 63 "Powerful digit counts"

The 5-digit number, 16807=75, is also a fifth power. Similarly, the 9-digit number, 134217728=89, is a ninth power.

How many n-digit positive integers exist which are also an nth power?

問 63 「べき乗の桁の個数」

5桁の数 16807 = 75は自然数を5乗した数である. 同様に9桁の数 134217728 = 89も自然数を9乗した数である.

自然数を n 乗して得られる n 桁の正整数は何個あるか?


fn main() {
    let mut count = 0u8;
    for a in 1..=9 {
        let exp = 1f32 / (1f32 - (a as f32).log10());
        println!("a: {} \t exp: {}", a, exp);
        count += exp as u8;
    }
    println!("{}", count);
    assert_eq!(count, 49);
}

fn main() {
    let mut count = 0u8;
    for a in 1u128..=9 {
        for exp in 1.. {
            let n = a.pow(exp);
            if n < 10u128.pow(exp - 1) {
                break;
            }
            println!("{} ^ {} \t = {}", a, exp, n);
            count += 1;
        }
    }
    println!("{}", count);
    assert_eq!(count, 49);
}
Problem 64 "Odd period square roots"

All square roots are periodic when written as continued fractions and can be written in the form:

\[ \quad \quad \sqrt{N}=a_0+\frac 1 {a_1+\frac 1 {a_2+ \frac 1 {a3+ \dots}}} \]

For example, let us consider \(\sqrt{23}:\)

\[\quad \quad \sqrt{23}=4+\sqrt{23}-4=4+\frac 1 {\frac 1 {\sqrt{23}-4}}=4+\frac 1 {1+\frac{\sqrt{23}-3}7}\]

If we continue we would get the following expansion:

\[ \quad \quad \sqrt{23}=4+\frac 1 {1+\frac 1 {3+ \frac 1 {1+\frac 1 {8+ \dots}}}} \]

The process can be summarised as follows:

\[ \quad \quad a_0=4, \frac 1 {\sqrt{23}-4}=\frac {\sqrt{23}+4} 7=1+\frac {\sqrt{23}-3} 7 \]
\[ \quad \quad a_1=1, \frac 7 {\sqrt{23}-3}=\frac {7(\sqrt{23}+3)} {14}=3+\frac {\sqrt{23}-3} 2 \]
\[ \quad \quad a_2=3, \frac 2 {\sqrt{23}-3}=\frac {2(\sqrt{23}+3)} {14}=1+\frac {\sqrt{23}-4} 7 \]
\[ \quad \quad a_3=1, \frac 7 {\sqrt{23}-4}=\frac {7(\sqrt{23}+4)} 7=8+\sqrt{23}-4 \]
\[ \quad \quad a_4=8, \frac 1 {\sqrt{23}-4}=\frac {\sqrt{23}+4} 7=1+\frac {\sqrt{23}-3} 7 \]
\[ \quad \quad a_5=1, \frac 7 {\sqrt{23}-3}=\frac {7 (\sqrt{23}+3)} {14}=3+\frac {\sqrt{23}-3} 2 \]
\[ \quad \quad a_6=3, \frac 2 {\sqrt{23}-3}=\frac {2(\sqrt{23}+3)} {14}=1+\frac {\sqrt{23}-4} 7 \]
\[ \quad \quad a_7=1, \frac 7 {\sqrt{23}-4}=\frac {7(\sqrt{23}+4)} {7}=8+\sqrt{23}-4 \]

It can be seen that the sequence is repeating. For conciseness, we use the notation \(\sqrt{23}=[4;(1,3,1,8)]\), to indicate that the block (1,3,1,8) repeats indefinitely.

The first ten continued fraction representations of (irrational) square roots are:

\(\quad \quad \sqrt{2}=[1;(2)] \), period=1
\(\quad \quad \sqrt{3}=[1;(1,2)] \), period=2
\(\quad \quad \sqrt{5}=[2;(4)] \), period=1
\(\quad \quad \sqrt{6}=[2;(2,4)] \), period=2
\(\quad \quad \sqrt{7}=[2;(1,1,1,4)] \), period=4
\(\quad \quad \sqrt{8}=[2;(1,4)] \), period=2
\(\quad \quad \sqrt{10}=[3;(6)] \), period=1
\(\quad \quad \sqrt{11}=[3;(3,6)] \), period=2
\(\quad \quad \sqrt{12}=[3;(2,6)] \), period=2
\(\quad \quad \sqrt{13}=[3;(1,1,1,1,6)] \), period=5

Exactly four continued fractions, for \(N \le 13\), have an odd period.

How many continued fractions for \(N \le 10\,000\) have an odd period?

問 64 「奇数周期の平方根」

平方根は連分数の形で表したときに周期的であり, 以下の形で書ける:

例えば, √23を考えよう.

となる.

この操作を続けていくと,

を得る.

操作を纏めると以下になる:

よって, この操作は繰り返しになることが分かる. 表記を簡潔にするために, √23 = [4;(1,3,1,8)]と表す. (1,3,1,8)のブロックは無限に繰り返される項を表している.

最初の10個の無理数である平方根を連分数で表すと以下になる.

  • √2=[1;(2)], period=1
  • √3=[1;(1,2)], period=2
  • √5=[2;(4)], period=1
  • √6=[2;(2,4)], period=2
  • √7=[2;(1,1,1,4)], period=4
  • √8=[2;(1,4)], period=2
  • √10=[3;(6)], period=1
  • √11=[3;(3,6)], period=2
  • √12= [3;(2,6)], period=2
  • √13=[3;(1,1,1,1,6)], period=5

N ≤ 13で奇数の周期をもつ平方根は丁度4つある.

N ≤ 10000 について奇数の周期をもつ平方根が何個あるか答えよ.


Real numbers

Continued fractions

Floor function


mod fraction {
    trait MixedFraction {
        fn integer_part(&self) -> u32;
    }

    pub struct QuadraticIrrational {
        rational_part: u32,
        irrational_part: u32,
        downscaling_ratio: u32,
        pub integer_part: u32,
        pub iteration: u32,
    }

    impl MixedFraction for QuadraticIrrational {
        fn integer_part(&self) -> u32 {
            let mixed_fraction
                = self.rational_part as f64 
                + (self.irrational_part as f64).sqrt();
            (mixed_fraction / self.downscaling_ratio as f64) as u32
        }
    }

    impl QuadraticIrrational {
        pub fn new(square_free_integer: u32) -> Self {
            assert!(
                ((square_free_integer as f64).sqrt() as u32).pow(2)
                != square_free_integer
            );
            let mut q = Self {
                rational_part: 0,
                irrational_part: square_free_integer,
                downscaling_ratio: 1,
                integer_part: u32::MAX,
                iteration: 0,
            };
            q.integer_part = q.integer_part();
            q
        }
        pub fn next_iteration(&mut self) {
            self.iteration += 1;
            self.rational_part 
                = self.downscaling_ratio 
                * self.integer_part 
                - self.rational_part;
            self.downscaling_ratio
                = (self.irrational_part - self.rational_part.pow(2)) 
                / self.downscaling_ratio;
            self.integer_part = self.integer_part();
        }
    }
}

fn main() {
    let mut count = 0u32;
    for n in 2..=10000 {
        if ((n as f64).sqrt() as u32).pow(2) == n {
            continue;
        }
        let mut surd = fraction::QuadraticIrrational::new(n);
        let integer_part_orig = surd.integer_part;
        while {
            surd.next_iteration();
            surd.integer_part != integer_part_orig * 2
        } {}
        if surd.iteration % 2 != 0 {
            count += 1;
        }
    }
    println!("{}", count);
    assert_eq!(count, 1322);
}
Problem 65 "Convergents of e"

The square root of 2 can be written as an infinite continued fraction.

\[\sqrt{2} = 1 + \dfrac{1}{2 + \dfrac{1}{2 + \dfrac{1}{2 + \dfrac{1}{2 + ...}}}}\]

The infinite continued fraction can be written, \(\sqrt{2} = [1; (2)]\), \((2)\) indicates that 2 repeats ad infinitum. In a similar way, \(\sqrt{23} = [4; (1, 3, 1, 8)]\).

It turns out that the sequence of partial values of continued fractions for square roots provide the best rational approximations. Let us consider the convergents for \(\sqrt{2}\).

\[ 1 + \dfrac{1}{2} = \dfrac{3}{2}\\ 1 + \dfrac{1}{2 + \dfrac{1}{2}} = \dfrac{7}{5}\\ 1 + \dfrac{1}{2 + \dfrac{1}{2 + \dfrac{1}{2}}} = \dfrac{17}{12}\\ 1 + \dfrac{1}{2 + \dfrac{1}{2 + \dfrac{1}{2 + \dfrac{1}{2}}}} = \dfrac{41}{29} \]

Hence the sequence of the first ten convergents for \(\sqrt{2}\) are:

\[1, \dfrac{3}{2}, \dfrac{7}{5}, \dfrac{17}{12}, \dfrac{41}{29}, \dfrac{99}{70}, \dfrac{239}{169}, \dfrac{577}{408}, \dfrac{1393}{985}, \dfrac{3363}{2378}, ...\]

What is most surprising is that the important mathematical constant,
\[e = [2; 1, 2, 1, 1, 4, 1, 1, 6, 1, ... , 1, 2k, 1, ...]\]

The first ten terms in the sequence of convergents for e are:

\[2, 3, \dfrac{8}{3}, \dfrac{11}{4}, \dfrac{19}{7}, \dfrac{87}{32}, \dfrac{106}{39}, \dfrac{193}{71}, \dfrac{1264}{465}, \dfrac{1457}{536}, ...\]

The sum of digits in the numerator of the 10th convergent is \(1 + 4 + 5 + 7 = 17\).

Find the sum of digits in the numerator of the 100th convergent of the continued fraction for \(e\).

問 65 「e の近似分数」

2の平方根は無限連分数として書くことができる.

無限連分数である √2 = [1;(2)] と書くことができるが, (2) は2が無限に繰り返されることを示す. 同様に, √23 = [4;(1,3,1,8)].

平方根の部分的な連分数の数列から良い有理近似が得られることが分かる.√2の近似分数について考えよう.

従って, √2の近似分数からなる数列の最初の10項は:

1, 3/2, 7/5, 17/12, 41/29, 99/70, 239/169, 577/408, 1393/985, 3363/2378, ...

もっとも驚くべきことに, 数学的に重要な定数,

e = [2; 1,2,1, 1,4,1, 1,6,1 , ... , 1,2k,1, ...].

e の近似分数からなる数列の最初の10項は:

2, 3, 8/3, 11/4, 19/7, 87/32, 106/39, 193/71, 1264/465, 1457/536, ...

10項目の近似分数の分子の桁を合計すると1+4+5+7=17である.

e についての連分数である近似分数の100項目の分子の桁の合計を求めよ.

Big numbers

mod bignum {
    #[derive(Clone)]
    pub struct BigNum {
        v: Vec<u64>,
    }

    impl BigNum {
        const TEN_MIL: u64 = 10_000_000_000;
        pub fn new(n: u8) -> Self {
            Self { v: vec![n as u64] }
        }
        fn merge(&mut self, page: usize, n: u64, carry: &mut u64) {
            if self.v.get(page).is_none() {
                self.v.push(0u64)
            }
            if let Some(con) = self.v.get_mut(page) {
                *con += n + *carry;
                if *con < Self::TEN_MIL {
                    *carry = 0;
                    return;
                }
                *carry = 1;
                *con -= Self::TEN_MIL;
            }
        }
        pub fn add(&mut self, b: &BigNum) {
            let mut p = 0usize;
            let mut carry = 0u64;
            let mut ite = b.v.iter();
            while let Some(n) = ite.next() {
                self.merge(p, *n, &mut carry);
                p += 1;
            }
            while carry != 0 {
                self.merge(p, 0, &mut carry);
                p += 1;
            }
        }
        pub fn multiply(&mut self, n: u8) {
            let mut carry = 0u64;
            for con in self.v.iter_mut() {
                *con = *con * n as u64 + carry;
                if *con < Self::TEN_MIL {
                    carry = 0;
                    continue;
                }
                carry = *con / Self::TEN_MIL;
                *con %= Self::TEN_MIL;
            }
            if carry != 0 {
                self.v.push(carry);
            }
        }
        pub fn digit_sum(&self) -> u32 {
            let mut sum = 0u32;
            for &con in &self.v {
                let mut t = con;
                while t > 0 {
                    sum += (t % 10) as u32;
                    t /= 10;
                }
            }
            sum
        }
    }
}

struct EulerNumberNumerator {
    prev: bignum::BigNum,
    value: bignum::BigNum,
    term: u8,
}

fn main() {
    let mut enn = EulerNumberNumerator {
        prev: bignum::BigNum::new(3),
        value: bignum::BigNum::new(8),
        term: 3,
    };
    while enn.term < 100 {
        enn.term += 1;
        let t = enn.value.clone();
        if enn.term % 3 == 0 {
            let k = enn.term / 3;
            enn.value.multiply(2 * k);
        }
        enn.value.add(&enn.prev);
        enn.prev = t;
    }
    let sum = enn.value.digit_sum();
    println!("{}", sum);
    assert_eq!(sum, 272);
}
Problem 66 "Diophantine equation"

Consider quadratic Diophantine equations of the form:

x2 – Dy2 = 1

For example, when D=13, the minimal solution in x is 6492 – 13×1802 = 1.

It can be assumed that there are no solutions in positive integers when D is square.

By finding minimal solutions in x for D = {2, 3, 5, 6, 7}, we obtain the following:

32 – 2×22 = 1
22 – 3×12 = 1
92 – 5×42 = 1
52 – 6×22 = 1
82 – 7×32 = 1

Hence, by considering minimal solutions in x for D ≤ 7, the largest x is obtained when D=5.

Find the value of D ≤ 1000 in minimal solutions of x for which the largest value of x is obtained.

問 66 「ディオファントス方程式」

次の形式の, 2次のディオファントス方程式を考えよう:

x2 – Dy2 = 1

たとえば D=13 のとき, xを最小にする解は x is 6492 – 13×1802 = 1.である.

D が平方数(square)のとき, 正整数のなかに解は存在しないと考えられる.

D = {2, 3, 5, 6, 7} に対して x を最小にする解は次のようになる:

32 – 2×22 = 1
22 – 3×12 = 1
92 – 5×42 = 1
52 – 6×22 = 1
82 – 7×32 = 1

したがって, D ≤ 7 に対して x を最小にする解を考えると, D=5 のとき x は最大である.

D ≤ 1000 に対する x を最小にする解で, x が最大になるような D の値を見つけよ.


Non primitive Pythagorean triples and parabolas

Continued fractions and their periods

x^2 - Dy^2 = 1 ⬄ √D ≈ x/y

mod fraction {
    trait MixedFraction {
        fn integer_part(&self) -> u32;
    }

    pub struct QuadraticIrrational {
        rational_part: u32,
        irrational_part: u32,
        downscaling_ratio: u32,
        pub integer_part: u32,
        pub iteration: u32,
        integers: Vec<u32>,
    }

    impl MixedFraction for QuadraticIrrational {
        fn integer_part(&self) -> u32 {
            let mixed_fraction 
                = self.rational_part as f64 
                + (self.irrational_part as f64).sqrt();
            (mixed_fraction / self.downscaling_ratio as f64) as u32
        }
    }

    impl QuadraticIrrational {
        pub fn new(square_free_integer: u32) -> Self {
            assert!(
                ((square_free_integer as f64).sqrt() as u32).pow(2)
                != square_free_integer
            );
            let mut q = Self {
                rational_part: 0,
                irrational_part: square_free_integer,
                downscaling_ratio: 1,
                integer_part: u32::MAX,
                iteration: 0,
                integers: vec![],
            };
            q.integer_part = q.integer_part();
            q.integers.push(q.integer_part);
            q
        }
        pub fn next_iteration(&mut self) {
            self.iteration += 1;
            self.rational_part
                = self.downscaling_ratio 
                * self.integer_part 
                - self.rational_part;
            self.downscaling_ratio
                = (self.irrational_part - self.rational_part.pow(2))
                / self.downscaling_ratio;
            self.integer_part = self.integer_part();
            self.integers.push(self.integer_part);
        }
        pub fn last_numerator_approx(&self) -> f64 {
            let mut result = self.integers[0] as f64;
            let mut term_before_last = 1f64;
            for a in (&self.integers[1..self.integers.len() - 1])
                .iter()
                .map(|&a| a as f64)
            {
                let t = result.clone();
                result *= a;
                result += term_before_last;
                term_before_last = t;
            }
            result
        }
        pub fn last_denominator_approx(&self) -> f64 {
            let mut result = 1f64;
            let mut term_before_last = 0f64;
            for a in (&self.integers[1..self.integers.len() - 1])
                .iter()
                .map(|&a| a as f64)
            {
                let t = result.clone();
                result *= a;
                result += term_before_last;
                term_before_last = t;
            }
            result
        }
    }
}

fn main() {
    let mut max_numerator_aprox = 0f64;
    let mut max_d = 0u32;
    for n in 2..=1000 {
        if ((n as f64).sqrt() as u32).pow(2) == n {
            continue;
        }
        let mut surd = fraction::QuadraticIrrational::new(n);
        let integer_part_orig = surd.integer_part;
        while {
            surd.next_iteration();
            surd.integer_part != integer_part_orig * 2 || surd.iteration % 2 != 0
        } {}
        let last_numerator_approx = surd.last_numerator_approx();
        if last_numerator_approx > max_numerator_aprox {
            max_numerator_aprox = last_numerator_approx;
            max_d = n;
        }
    }

    println!("{}", max_d);
    assert_eq!(max_d, 661);
}
Problem 67 "Maximum path sum II"

By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.

3
7 4
2 4 6
8 5 9 3

That is, 3 + 7 + 4 + 9 = 23.

Find the maximum total from top to bottom in triangle.txt, a 15K text file containing a triangle with one-hundred rows.

NOTE: This is a much more difficult version of Problem 18. It is not possible to try every route to solve this problem, as there are 299 altogether! If you could check one trillion (1012) routes every second it would take over twenty billion years to check them all. There is an efficient algorithm to solve it. ;o)

問 67 「最大経路の和 その2」

fn main() {
    let mut triangle: Vec<Vec<u16>> = data();
    triangle.push(vec![0; triangle.last().unwrap().len() + 1]);
    for y in (0..triangle.len() - 1).rev() {
        for x in 0..triangle[y].len() {
            let a = triangle[y + 1][x];
            let b = triangle[y + 1][x + 1];
            triangle[y][x] += std::cmp::max(a, b);
        }
    }
    let sum = triangle[0][0];

    println!("{}", sum);
    assert_eq!(sum, 635);
}

fn data() -> Vec<Vec<u16>> {
    vec![
        vec![59],
        vec![73,41],
        vec![52,40,09],
        vec![26,53,06,34],
        vec![10,51,87,86,81],
        vec![61,95,66,57,25,68],
        vec![90,81,80,38,92,67,73],
        vec![30,28,51,76,81,18,75,44],
        vec![84,14,95,87,62,81,17,78,58]
    ]
}
Problem 68 "Magic 5-gon ring"

Consider the following "magic" 3-gon ring, filled with the numbers 1 to 6, and each line adding to nine.


Working clockwise, and starting from the group of three with the numerically lowest external node (4,3,2 in this example), each solution can be described uniquely. For example, the above solution can be described by the set: 4,3,2; 6,2,1; 5,1,3.

It is possible to complete the ring with four different totals: 9, 10, 11, and 12. There are eight solutions in total.

TotalSolution Set
94,2,3; 5,3,1; 6,1,2
94,3,2; 6,2,1; 5,1,3
102,3,5; 4,5,1; 6,1,3
102,5,3; 6,3,1; 4,1,5
111,4,6; 3,6,2; 5,2,4
111,6,4; 5,4,2; 3,2,6
121,5,6; 2,6,4; 3,4,5
121,6,5; 3,5,4; 2,4,6

By concatenating each group it is possible to form 9-digit strings; the maximum string for a 3-gon ring is 432621513.

Using the numbers 1 to 10, and depending on arrangements, it is possible to form 16- and 17-digit strings. What is the maximum 16-digit string for a "magic" 5-gon ring?


問 68 「マジックペンタゴン」

下に示す図のようなものを"magic" 3-gon ringという. これは1~6の数字を当てはめて, 各列の数字の和が9となっている. これを例として説明する.

外側のノードのうち一番小さいものの付いた列(例では4,3,2)から時計回りに回ってそれぞれ列の数字を3つ連ねて説明する. 例えば例のものは4,3,2; 6,2,1; 5,1,3という組で説明することができる.

1~6の数字を当てはめて, 各列の数字の和が等しくなるものは次の8通りある.

この組の各数字を連結して, 9桁の数字で表すことができる. 例えば, 上の図のものは4,3,2; 6,2,1; 5,1,3であるので432621513である.

さて, 下の図に1~10の数字を当てはめ, 各列の数字の和が等しくなる"magic" 5-gon ringを作って, それを表す16桁または17桁の数字のうち, 16桁のものの最大の数字を答えよ.

Generation of permurations using recursion

#[derive(Clone)]
struct MagicGonRing {
    mat: [Vec<u8>; 3],
    width: usize,
}

impl MagicGonRing {
    fn new(ngon: u8) -> Self {
        let n = ngon as usize;
        Self {
            mat: [vec![0u8; n], vec![0u8; n], vec![0u8; n]],
            width: n,
        }
    }
    fn fill(&mut self, initial: u8) -> Vec<MagicGonRing> {
        assert!(initial > 0 && initial <= self.width as u8 * 2);
        self.mat[0][0] = initial;
        let used = 1u32 << initial;
        let mut perfect_rings: Vec<MagicGonRing> = vec![];
        self.dig(used, 0, 1, &mut perfect_rings);
        perfect_rings
    }
    fn is_rotational_variation(&self, y: usize, n: u8) -> bool {
        y == 0 && n < self.mat[0][0]
    }
    fn is_violation_of_homogeneity(&mut self, x: usize, y: usize, n: u8) -> bool {
        if y == 0 || x == 0 {
            return false;
        }
        let total = self.mat[0][x - 1] + self.mat[1][x - 1] + n;
        if x == 1 {
            self.mat[2][x] = total;
            return false;
        }
        if self.mat[2][x - 1] != total {
            return true;
        }
        if x == self.width - 1 {
            let conjunction = self.mat[0][x] + n + self.mat[1][0];
            if conjunction != total {
                return true;
            }
            self.mat[2][0] = conjunction;
        }
        self.mat[2][x] = total;
        false
    }
    fn dig(&mut self, used: u32, x: usize, y: usize, drain: &mut Vec<MagicGonRing>) {
        if x > self.width - 1 {
            drain.push(self.clone());
            return;
        }
        let numbers = 1..=2 * self.width as u8;
        for n in numbers.filter(|&n| 1 << n & used == 0) {
            if self.is_rotational_variation(y, n) {
                continue;
            }
            if self.is_violation_of_homogeneity(x, y, n) {
                continue;
            }
            self.mat[y][x] = n;
            self.dig(used | 1u32 << n, x + y, y ^ 1, drain);
        }
    }
    fn stringfy(&self) -> String {
        let mut s = String::new();
        for i in 0..self.width {
            s.push_str(self.mat[0][i].to_string().as_str());
            s.push_str(self.mat[1][i].to_string().as_str());
            let conjunction = if i != self.width - 1 { i + 1 } else { 0 };
            s.push_str(self.mat[1][conjunction].to_string().as_str());
        }
        s
    }
}

fn main() {
    {
        let mut ring = MagicGonRing::new(3);
        for initial in (1u8..=6).rev() {
            let perfect_rings = ring.fill(initial);
            perfect_rings.iter().for_each(|g| println!("{:?}", g.mat));
        }
    }
    {
        let mut ans = None;
        let mut ring = MagicGonRing::new(3);
        for initial in (1u8..=4).rev() {
            let perfect_rings = ring.fill(initial);
            let mut list = perfect_rings
                .iter()
                .map(|g| g.stringfy())
                .collect::<Vec<String>>();
            list.sort();
            if let Some(s) = list.pop() {
                ans.insert(s);
                break;
            }
        }
        let ans = ans.expect("answer must exist");
        println!("{}", ans);
        assert_eq!(ans, "432621513");
    }
    {
        let mut ans = None;
        let mut ring = MagicGonRing::new(5);
        for initial in (1u8..=6).rev() {
            let perfect_rings = ring.fill(initial);
            let mut list = perfect_rings
                .iter()
                .map(|g| g.stringfy())
                .filter(|s| s.len() == 16)
                .collect::<Vec<String>>();
            list.sort();
            if let Some(s) = list.pop() {
                ans.insert(s);
                break;
            }
        }
        let ans = ans.expect("answer must exist");
        println!("{}", ans);
        assert_eq!(ans, "6531031914842725");
    }
}
Problem 81 "Path sum: two ways"

In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by only moving to the right and down, is indicated in bold red and is equal to 2427.

$$ \begin{pmatrix} \color{red}{131} & 673 & 234 & 103 & 18\\ \color{red}{201} & \color{red}{96} & \color{red}{342} & 965 & 150\\ 630 & 803 & \color{red}{746} & \color{red}{422} & 111\\ 537 & 699 & 497 & \color{red}{121} & 956\\ 805 & 732 & 524 & \color{red}{37} & \color{red}{331} \end{pmatrix} $$

Find the minimal path sum from the top left to the bottom right by only moving right and down in matrix.txt, a 31K text file containing an 80 by 80 matrix.

問 81 「経路の和:2方向」

下記の5次の正方行列で, 左上のセルから開始し右下のセルで終わるパスを探索する.

ただし下方向と右方向にのみ移動できるものとする.

通過したセルの和が最小となるパスは赤の太字で示されたもので, その値は2427である.

今, 31Kのテキストファイmatrix.txtには80×80の行列が書かれている.

同様に左上のセルから開始し右下のセルで終わり, かつ右方向と下方向にのみ移動するときの最小のパスの和を求めよ.

Since the dataset of the question is too large, it's using a mini set.

fn main() {
    let mut table = vec![
        vec![131, 673, 234, 103, 18],
        vec![201, 96, 342, 965, 150],
        vec![630, 803, 746, 422, 111],
        vec![537, 699, 497, 121, 956],
        vec![805, 732, 524, 37, 331]
    ];
    for y in 0..table.len() {
        for x in 0..table[0].len() {
            table[y][x] += match (y, x) {
                (0, 0) => continue,
                (0, _) => table[y][x - 1],
                (_, 0) => table[y - 1][x],
                _ => std::cmp::min(table[y][x - 1], table[y - 1][x]),
            }
        }
    }
    let min = table[table.len() - 1][table[table.len() - 1].len() - 1];

    println!("{}", min);
    assert_eq!(min, 2427);
}
Problem 82 "Path sum: three ways"

NOTE: This problem is a more challenging version of Problem 81.

The minimal path sum in the 5 by 5 matrix below, by starting in any cell in the left column and finishing in any cell in the right column, and only moving up, down, and right, is indicated in red and bold; the sum is equal to 994.

$$ \begin{pmatrix} 131 & 673 & \color{red}{234} & \color{red}{103} & \color{red}{18}\\ \color{red}{201} & \color{red}{96} & \color{red}{342} & 965 & 150\\ 630 & 803 & 746 & 422 & 111\\ 537 & 699 & 497 & 121 & 956\\ 805 & 732 & 524 & 37 & 331 \end{pmatrix} $$

Find the minimal path sum from the left column to the right column in matrix.txt, a 31K text file containing an 80 by 80 matrix.

問 82 「経路の和:3方向」

注: この問題はProblem 81よりも挑戦しがいがあるだろう.

下記の5次の正方行列で, 一番左の列の任意のセルから開始し一番右の列の任意のセルで終わる道を探索する. ただし上下右にのみ移動できるものとする. 一番小さなパスは下で赤の太字で示されたものである. このときの合計は994になる.

今, 31Kのテキストファイルmatrix.txtには80×80の行列が書かれている. 一番左の列から一番右の列へ移動する際の一番小さなパスの和を求めよ.

Since the dataset of the question is too large, it's using a mini set.

fn row_internal_loop(
    col: usize,
    row: usize,
    table: &[[u32; 5]; 5],
    determineds: &Vec<u32>,
) -> u32 {
    let mut min = u32::MAX;
    {
        let mut d = 0u32;
        for r in (0..row).rev() {
            d += table[r][col];
            min = std::cmp::min(min, determineds[r] + d);
        }
    }
    min = std::cmp::min(min, determineds[row]);
    {
        let mut d = 0u32;
        for r in row + 1..table.len() {
            d += table[r][col];
            min = std::cmp::min(min, determineds[r] + d);
        }
    }
    min
}

fn main() {
    let table: [[u32; 5]; 5] = [
        [131, 673, 234, 103, 18],
        [201, 96, 342, 965, 150],
        [630, 803, 746, 422, 111],
        [537, 699, 497, 121, 956],
        [805, 732, 524, 37, 331]
    ];
    let mut determineds = vec![0u32; table.len()];
    let mut estimations = vec![0u32; table.len()];
    for col in 0..table[0].len() {
        for row in 0..table.len() {
            let min = row_internal_loop(col, row, &table, &determineds);
            estimations[row] = table[row][col] + min;
        }
        determineds.clone_from(&estimations);
    }
    let min = estimations
        .iter()
        .min()
        .map(|&m| m)
        .expect("the input table must have at least one row");

    println!("{}", min);
    assert_eq!(min, 994);
}
Problem 83 "Path sum: four ways"

NOTE: This problem is a significantly more challenging version of Problem 81.

In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by moving left, right, up, and down, is indicated in bold red and is equal to 2297.

$$ \begin{pmatrix} \color{red}{131} & 673 & \color{red}{234} & \color{red}{103} & \color{red}{18}\\ \color{red}{201} & \color{red}{96} & \color{red}{342} & 965 & \color{red}{150}\\ 630 & 803 & 746 & \color{red}{422} & \color{red}{111}\\ 537 & 699 & 497 & \color{red}{121} & 956\\ 805 & 732 & 524 & \color{red}{37} & \color{red}{331} \end{pmatrix} $$

Find the minimal path sum from the top left to the bottom right by moving left, right, up, and down in matrix.txt, a 31K text file containing an 80 by 80 matrix.

問 83 「経路の和:4方向」

注: この問題はProblem 81よりも非常に挑戦しがいがあるだろう.

下記の5次の正方行列で, 上下左右に移動し左上のセルから開始し右下のセルで終了する道を探索

今, 31Kのテキストファイルmatrix.txtには80×80の行列が書かれている. 上下左右に移動し左上のセルから開始し右下のセルで終了する道に沿った和の最小を求めよ.

Since the dataset of the question is too large, it's using a mini set.

use std::{cmp::Ordering, collections::BinaryHeap};

#[derive(Copy, Clone, Eq, PartialEq)]
struct Vertex {
    cost: u32,
    xy: (usize, usize),
}

impl Ord for Vertex {
    fn cmp(&self, other: &Self) -> Ordering {
        other.cost.cmp(&self.cost)
    }
}

impl PartialOrd for Vertex {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

fn update_adjacents(
    v: Vertex,
    table: &[[u32; 5]; 5],
    visited: &Vec<Vec<bool>>,
    estimations: &mut Vec<Vec<u32>>,
    pq: &mut BinaryHeap<Vertex>,
) {
    let Vertex { xy: (x, y), cost } = v;
    if y > 0 {
        let t = y - 1;
        if !visited[t][x] {
            let e = &mut estimations[t][x];
            *e = std::cmp::min(*e, table[t][x] + cost);
            pq.push(Vertex {
                cost: *e,
                xy: (x, t),
            });
        }
    }
    if x < table[0].len() - 1 {
        let t = x + 1;
        if !visited[y][t] {
            let e = &mut estimations[y][t];
            *e = std::cmp::min(*e, table[y][t] + cost);
            pq.push(Vertex {
                cost: *e,
                xy: (t, y),
            });
        }
    }
    if y < table.len() - 1 {
        let t = y + 1;
        if !visited[t][x] {
            let e = &mut estimations[t][x];
            *e = std::cmp::min(*e, table[t][x] + cost);
            pq.push(Vertex {
                cost: *e,
                xy: (x, t),
            });
        }
    }
    if x > 0 {
        let t = x - 1;
        if !visited[y][t] {
            let e = &mut estimations[y][t];
            *e = std::cmp::min(*e, table[y][t] + cost);
            pq.push(Vertex {
                cost: *e,
                xy: (t, y),
            });
        }
    }
}

fn suggest_next_vertex(pq: &mut BinaryHeap<Vertex>, visited: &Vec<Vec<bool>>) -> Option<Vertex> {
    loop {
        match pq.pop() {
            None => return None,
            Some(v) if !visited[v.xy.1][v.xy.0] => return Some(v),
            _ => (),
        }
    }
}

fn main() {
    let table: [[u32; 5]; 5] = [
        [131, 673, 234, 103, 18],
        [201, 96, 342, 965, 150],
        [630, 803, 746, 422, 111],
        [537, 699, 497, 121, 956],
        [805, 732, 524, 37, 331]
    ];
    let (w, h) = (table[0].len(), table.len());
    let mut visited = vec![vec![false; w]; h];
    let mut estimations = vec![vec![u32::MAX; w]; h];

    estimations[0][0] = table[0][0];
    let mut pq = std::collections::BinaryHeap::<Vertex>::new();
    pq.push(Vertex {
        cost: estimations[0][0],
        xy: (0, 0),
    });
    let is_goal = |x, y| -> bool { x == w - 1 && y == h - 1 };
    let min = loop {
        let vertex = suggest_next_vertex(&mut pq, &visited)
            .expect("Goal was unreachable!");
        let (x, y) = vertex.xy;
        if is_goal(x, y) {
            break vertex.cost;
        }
        visited[y][x] = true;
        update_adjacents(vertex, &table, &visited, &mut estimations, &mut pq);
    };

    println!("{}", min);
    assert_eq!(min, 2297);
}

TODO: implement a primarity queue by myself


fn update_adjacents(
    x: usize,
    y: usize,
    table: &[[u32; 5]; 5],
    visited: &Vec<Vec<bool>>,
    estimations: &mut Vec<Vec<u32>>,
) {
    let cost = estimations[y][x];
    if y > 0 {
        let t = y - 1;
        if !visited[t][x] {
            let e = &mut estimations[t][x];
            *e = std::cmp::min(*e, table[t][x] + cost);
        }
    }
    if x < table[0].len() - 1 {
        let t = x + 1;
        if !visited[y][t] {
            let e = &mut estimations[y][t];
            *e = std::cmp::min(*e, table[y][t] + cost);
        }
    }
    if y < table.len() - 1 {
        let t = y + 1;
        if !visited[t][x] {
            let e = &mut estimations[t][x];
            *e = std::cmp::min(*e, table[t][x] + cost);
        }
    }
    if x > 0 {
        let t = x - 1;
        if !visited[y][t] {
            let e = &mut estimations[y][t];
            *e = std::cmp::min(*e, table[y][t] + cost);
        }
    }
}

fn suggest_next_vertex(
    table: &[[u32; 5]; 5],
    visited: &Vec<Vec<bool>>,
    estimations: &Vec<Vec<u32>>,
) -> Option<(usize, usize)> {
    let mut next: Option<(usize, usize)> = None;
    let mut minimum_estimation = u32::MAX;
    for y in 0..table.len() {
        for x in 0..table[0].len() {
            if visited[y][x] {
                continue;
            }
            if estimations[y][x] < minimum_estimation {
                minimum_estimation = estimations[y][x];
                next = Some((x, y));
            }
        }
    }
    next
}

fn main() {
    let table: [[u32; 5]; 5] = [
        [131, 673, 234, 103, 18],
        [201, 96, 342, 965, 150],
        [630, 803, 746, 422, 111],
        [537, 699, 497, 121, 956],
        [805, 732, 524, 37, 331]
    ];
    let (w, h) = (table[0].len(), table.len());
    let mut visited = vec![vec![false; w]; h];
    let mut estimations = vec![vec![u32::MAX; w]; h];

    estimations[0][0] = table[0][0];
    let is_goal = |x, y| -> bool { x == w - 1 && y == h - 1 };
    let min = loop {
        let (x, y) = suggest_next_vertex(&table, &visited, &estimations)
            .expect("Goal was unreachable!");
        if is_goal(x, y) {
            break estimations[y][x];
        }
        visited[y][x] = true;
        update_adjacents(x, y, &table, &visited, &mut estimations);
    };

    println!("{}", min);
    assert_eq!(min, 2297);
}
bash
<style type="text/css">

/----------------------------------------------------------------------------- | Copyright (c) Jupyter Development Team. | Distributed under the terms of the Modified BSD License. |----------------------------------------------------------------------------/

/* The following CSS variables define the main, public API for styling JupyterLab. These variables should be used by all plugins wherever possible. In other words, plugins should not define custom colors, sizes, etc unless absolutely necessary. This enables users to change the visual theme of JupyterLab by changing these variables.

Many variables appear in an ordered sequence (0,1,2,3). These sequences are designed to work well together, so for example, --jp-border-color1 should be used with --jp-layout-color1. The numbers have the following meanings:

  • 0: super-primary, reserved for special emphasis
  • 1: primary, most important under normal situations
  • 2: secondary, next most important under normal situations
  • 3: tertiary, next most important under normal situations

Throughout JupyterLab, we are mostly following principles from Google's Material Design when selecting colors. We are not, however, following all of MD as it is not optimized for dense, information rich UIs. */

:root { /* Elevation

  • We style box-shadows using Material Design's idea of elevation. These particular numbers are taken from here:
  • https://github.com/material-components/material-components-web
  • https://material-components-web.appspot.com/elevation.html */

--jp-shadow-base-lightness: 0; --jp-shadow-umbra-color: rgba( var(--jp-shadow-base-lightness), var(--jp-shadow-base-lightness), var(--jp-shadow-base-lightness), 0.2 ); --jp-shadow-penumbra-color: rgba( var(--jp-shadow-base-lightness), var(--jp-shadow-base-lightness), var(--jp-shadow-base-lightness), 0.14 ); --jp-shadow-ambient-color: rgba( var(--jp-shadow-base-lightness), var(--jp-shadow-base-lightness), var(--jp-shadow-base-lightness), 0.12 ); --jp-elevation-z0: none; --jp-elevation-z1: 0px 2px 1px -1px var(--jp-shadow-umbra-color), 0px 1px 1px 0px var(--jp-shadow-penumbra-color), 0px 1px 3px 0px var(--jp-shadow-ambient-color); --jp-elevation-z2: 0px 3px 1px -2px var(--jp-shadow-umbra-color), 0px 2px 2px 0px var(--jp-shadow-penumbra-color), 0px 1px 5px 0px var(--jp-shadow-ambient-color); --jp-elevation-z4: 0px 2px 4px -1px var(--jp-shadow-umbra-color), 0px 4px 5px 0px var(--jp-shadow-penumbra-color), 0px 1px 10px 0px var(--jp-shadow-ambient-color); --jp-elevation-z6: 0px 3px 5px -1px var(--jp-shadow-umbra-color), 0px 6px 10px 0px var(--jp-shadow-penumbra-color), 0px 1px 18px 0px var(--jp-shadow-ambient-color); --jp-elevation-z8: 0px 5px 5px -3px var(--jp-shadow-umbra-color), 0px 8px 10px 1px var(--jp-shadow-penumbra-color), 0px 3px 14px 2px var(--jp-shadow-ambient-color); --jp-elevation-z12: 0px 7px 8px -4px var(--jp-shadow-umbra-color), 0px 12px 17px 2px var(--jp-shadow-penumbra-color), 0px 5px 22px 4px var(--jp-shadow-ambient-color); --jp-elevation-z16: 0px 8px 10px -5px var(--jp-shadow-umbra-color), 0px 16px 24px 2px var(--jp-shadow-penumbra-color), 0px 6px 30px 5px var(--jp-shadow-ambient-color); --jp-elevation-z20: 0px 10px 13px -6px var(--jp-shadow-umbra-color), 0px 20px 31px 3px var(--jp-shadow-penumbra-color), 0px 8px 38px 7px var(--jp-shadow-ambient-color); --jp-elevation-z24: 0px 11px 15px -7px var(--jp-shadow-umbra-color), 0px 24px 38px 3px var(--jp-shadow-penumbra-color), 0px 9px 46px 8px var(--jp-shadow-ambient-color);

/* Borders

  • The following variables, specify the visual styling of borders in JupyterLab. */

--jp-border-width: 1px; --jp-border-color0: var(--md-grey-400); --jp-border-color1: var(--md-grey-400); --jp-border-color2: var(--md-grey-300); --jp-border-color3: var(--md-grey-200); --jp-border-radius: 2px;

/* UI Fonts

  • The UI font CSS variables are used for the typography all of the JupyterLab
  • user interface elements that are not directly user generated content.
  • The font sizing here is done assuming that the body font size of --jp-ui-font-size1
  • is applied to a parent element. When children elements, such as headings, are sized
  • in em all things will be computed relative to that body size. */

--jp-ui-font-scale-factor: 1.2; --jp-ui-font-size0: 0.83333em; --jp-ui-font-size1: 13px; /* Base font size */ --jp-ui-font-size2: 1.2em; --jp-ui-font-size3: 1.44em;

--jp-ui-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';

/*

  • Use these font colors against the corresponding main layout colors.
  • In a light theme, these go from dark to light. */

/* Defaults use Material Design specification */ --jp-ui-font-color0: rgba(0, 0, 0, 1); --jp-ui-font-color1: rgba(0, 0, 0, 0.87); --jp-ui-font-color2: rgba(0, 0, 0, 0.54); --jp-ui-font-color3: rgba(0, 0, 0, 0.38);

/*

  • Use these against the brand/accent/warn/error colors.
  • These will typically go from light to darker, in both a dark and light theme. */

--jp-ui-inverse-font-color0: rgba(255, 255, 255, 1); --jp-ui-inverse-font-color1: rgba(255, 255, 255, 1); --jp-ui-inverse-font-color2: rgba(255, 255, 255, 0.7); --jp-ui-inverse-font-color3: rgba(255, 255, 255, 0.5);

/* Content Fonts

  • Content font variables are used for typography of user generated content.
  • The font sizing here is done assuming that the body font size of --jp-content-font-size1
  • is applied to a parent element. When children elements, such as headings, are sized
  • in em all things will be computed relative to that body size. */

--jp-content-line-height: 1.6; --jp-content-font-scale-factor: 1.2; --jp-content-font-size0: 0.83333em; --jp-content-font-size1: 14px; /* Base font size */ --jp-content-font-size2: 1.2em; --jp-content-font-size3: 1.44em; --jp-content-font-size4: 1.728em; --jp-content-font-size5: 2.0736em;

/* This gives a magnification of about 125% in presentation mode over normal. */ --jp-content-presentation-font-size1: 17px;

--jp-content-heading-line-height: 1; --jp-content-heading-margin-top: 1.2em; --jp-content-heading-margin-bottom: 0.8em; --jp-content-heading-font-weight: 500;

/* Defaults use Material Design specification */ --jp-content-font-color0: rgba(0, 0, 0, 1); --jp-content-font-color1: rgba(0, 0, 0, 0.87); --jp-content-font-color2: rgba(0, 0, 0, 0.54); --jp-content-font-color3: rgba(0, 0, 0, 0.38);

--jp-content-link-color: var(--md-blue-700);

--jp-content-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';

/*

  • Code Fonts
  • Code font variables are used for typography of code and other monospaces content. */

--jp-code-font-size: 13px; --jp-code-line-height: 1.3077; /* 17px for 13px base / --jp-code-padding: 5px; / 5px for 13px base, codemirror highlighting needs integer px value */ --jp-code-font-family-default: Menlo, Consolas, 'DejaVu Sans Mono', monospace; --jp-code-font-family: var(--jp-code-font-family-default);

/* This gives a magnification of about 125% in presentation mode over normal. */ --jp-code-presentation-font-size: 16px;

/* may need to tweak cursor width if you change font size */ --jp-code-cursor-width0: 1.4px; --jp-code-cursor-width1: 2px; --jp-code-cursor-width2: 4px;

/* Layout

  • The following are the main layout colors use in JupyterLab. In a light
  • theme these would go from light to dark. */

--jp-layout-color0: white; --jp-layout-color1: white; --jp-layout-color2: var(--md-grey-200); --jp-layout-color3: var(--md-grey-400); --jp-layout-color4: var(--md-grey-600);

/* Inverse Layout

  • The following are the inverse layout colors use in JupyterLab. In a light
  • theme these would go from dark to light. */

--jp-inverse-layout-color0: #111111; --jp-inverse-layout-color1: var(--md-grey-900); --jp-inverse-layout-color2: var(--md-grey-800); --jp-inverse-layout-color3: var(--md-grey-700); --jp-inverse-layout-color4: var(--md-grey-600);

/* Brand/accent */

--jp-brand-color0: var(--md-blue-900); --jp-brand-color1: var(--md-blue-700); --jp-brand-color2: var(--md-blue-300); --jp-brand-color3: var(--md-blue-100); --jp-brand-color4: var(--md-blue-50);

--jp-accent-color0: var(--md-green-900); --jp-accent-color1: var(--md-green-700); --jp-accent-color2: var(--md-green-300); --jp-accent-color3: var(--md-green-100);

/* State colors (warn, error, success, info) */

--jp-warn-color0: var(--md-orange-900); --jp-warn-color1: var(--md-orange-700); --jp-warn-color2: var(--md-orange-300); --jp-warn-color3: var(--md-orange-100);

--jp-error-color0: var(--md-red-900); --jp-error-color1: var(--md-red-700); --jp-error-color2: var(--md-red-300); --jp-error-color3: var(--md-red-100);

--jp-success-color0: var(--md-green-900); --jp-success-color1: var(--md-green-700); --jp-success-color2: var(--md-green-300); --jp-success-color3: var(--md-green-100);

--jp-info-color0: var(--md-cyan-900); --jp-info-color1: var(--md-cyan-700); --jp-info-color2: var(--md-cyan-300); --jp-info-color3: var(--md-cyan-100);

/* Cell specific styles */

--jp-cell-padding: 5px;

--jp-cell-collapser-width: 8px; --jp-cell-collapser-min-height: 20px; --jp-cell-collapser-not-active-hover-opacity: 0.6;

--jp-cell-editor-background: var(--md-grey-100); --jp-cell-editor-border-color: var(--md-grey-300); --jp-cell-editor-box-shadow: inset 0 0 2px var(--md-blue-300); --jp-cell-editor-active-background: var(--jp-layout-color0); --jp-cell-editor-active-border-color: var(--jp-brand-color1);

--jp-cell-prompt-width: 64px; --jp-cell-prompt-font-family: var(--jp-code-font-family-default); --jp-cell-prompt-letter-spacing: 0px; --jp-cell-prompt-opacity: 1; --jp-cell-prompt-not-active-opacity: 0.5; --jp-cell-prompt-not-active-font-color: var(--md-grey-700); /* A custom blend of MD grey and blue 600

  • See https://meyerweb.com/eric/tools/color-blend/#546E7A:1E88E5:5:hex / --jp-cell-inprompt-font-color: #307fc1; / A custom blend of MD grey and orange 600
  • https://meyerweb.com/eric/tools/color-blend/#546E7A:F4511E:5:hex */ --jp-cell-outprompt-font-color: #bf5b3d;

/* Notebook specific styles */

--jp-notebook-padding: 10px; --jp-notebook-select-background: var(--jp-layout-color1); --jp-notebook-multiselected-color: var(--md-blue-50);

/* The scroll padding is calculated to fill enough space at the bottom of the notebook to show one single-line cell (with appropriate padding) at the top when the notebook is scrolled all the way to the bottom. We also subtract one pixel so that no scrollbar appears if we have just one single-line cell in the notebook. This padding is to enable a 'scroll past end' feature in a notebook. */ --jp-notebook-scroll-padding: calc( 100% - var(--jp-code-font-size) * var(--jp-code-line-height) - var(--jp-code-padding) - var(--jp-cell-padding) - 1px );

/* Rendermime styles */

--jp-rendermime-error-background: #fdd; --jp-rendermime-table-row-background: var(--md-grey-100); --jp-rendermime-table-row-hover-background: var(--md-light-blue-50);

/* Dialog specific styles */

--jp-dialog-background: rgba(0, 0, 0, 0.25);

/* Console specific styles */

--jp-console-padding: 10px;

/* Toolbar specific styles */

--jp-toolbar-border-color: var(--jp-border-color1); --jp-toolbar-micro-height: 8px; --jp-toolbar-background: var(--jp-layout-color1); --jp-toolbar-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.24); --jp-toolbar-header-margin: 4px 4px 0px 4px; --jp-toolbar-active-background: var(--md-grey-300);

/* Statusbar specific styles */

--jp-statusbar-height: 24px;

/* Input field styles */

--jp-input-box-shadow: inset 0 0 2px var(--md-blue-300); --jp-input-active-background: var(--jp-layout-color1); --jp-input-hover-background: var(--jp-layout-color1); --jp-input-background: var(--md-grey-100); --jp-input-border-color: var(--jp-border-color1); --jp-input-active-border-color: var(--jp-brand-color1); --jp-input-active-box-shadow-color: rgba(19, 124, 189, 0.3);

/* General editor styles */

--jp-editor-selected-background: #d9d9d9; --jp-editor-selected-focused-background: #d7d4f0; --jp-editor-cursor-color: var(--jp-ui-font-color0);

/* Code mirror specific styles */

--jp-mirror-editor-keyword-color: #008000; --jp-mirror-editor-atom-color: #88f; --jp-mirror-editor-number-color: #080; --jp-mirror-editor-def-color: #00f; --jp-mirror-editor-variable-color: var(--md-grey-900); --jp-mirror-editor-variable-2-color: #05a; --jp-mirror-editor-variable-3-color: #085; --jp-mirror-editor-punctuation-color: #05a; --jp-mirror-editor-property-color: #05a; --jp-mirror-editor-operator-color: #aa22ff; --jp-mirror-editor-comment-color: #408080; --jp-mirror-editor-string-color: #ba2121; --jp-mirror-editor-string-2-color: #708; --jp-mirror-editor-meta-color: #aa22ff; --jp-mirror-editor-qualifier-color: #555; --jp-mirror-editor-builtin-color: #008000; --jp-mirror-editor-bracket-color: #997; --jp-mirror-editor-tag-color: #170; --jp-mirror-editor-attribute-color: #00c; --jp-mirror-editor-header-color: blue; --jp-mirror-editor-quote-color: #090; --jp-mirror-editor-link-color: #00c; --jp-mirror-editor-error-color: #f00; --jp-mirror-editor-hr-color: #999;

/* Vega extension styles */

--jp-vega-background: white;

/* Sidebar-related styles */

--jp-sidebar-min-width: 250px;

/* Search-related styles */

--jp-search-toggle-off-opacity: 0.5; --jp-search-toggle-hover-opacity: 0.8; --jp-search-toggle-on-opacity: 1; --jp-search-selected-match-background-color: rgb(245, 200, 0); --jp-search-selected-match-color: black; --jp-search-unselected-match-background-color: var( --jp-inverse-layout-color0 ); --jp-search-unselected-match-color: var(--jp-ui-inverse-font-color0);

/* Icon colors that work well with light or dark backgrounds */ --jp-icon-contrast-color0: var(--md-purple-600); --jp-icon-contrast-color1: var(--md-green-600); --jp-icon-contrast-color2: var(--md-pink-600); --jp-icon-contrast-color3: var(--md-blue-600); }

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS_CHTML-full,Safe"> </script>
<!-- MathJax configuration -->
<script type="text/x-mathjax-config">
init_mathjax = function() {
    if (window.MathJax) {
    // MathJax loaded
        MathJax.Hub.Config({
            TeX: {
                equationNumbers: {
                autoNumber: "AMS",
                useLabelIds: true
                }
            },
            tex2jax: {
                inlineMath: [ ['$','$'], ["\\(","\\)"] ],
                displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
                processEscapes: true,
                processEnvironments: true
            },
            displayAlign: 'center',
            CommonHTML: {
                linebreaks: { 
                automatic: true 
                }
            }
        });
    
        MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
    }
}
init_mathjax();
</script>
<!-- End of mathjax configuration --></head>