Problem Summary

A positive integer is called reachable if it can be obtained from the digits

1,2,3,4,5,6,7,8,9

used in this exact order and exactly once each, under the following rules:

1. Between two consecutive digits we may place one of the four binary operations +, -, *, /, or we may concatenate the digits.

2. Parentheses may be inserted arbitrarily.

3. Unary minus is not allowed.

The goal is to find the sum of all distinct positive integers that are reachable exactly.

Mathematical Approach

1. Encoding Every Admissible Expression

There are 8 gaps between the 9 digits. In each gap we choose one symbol from

$$\{+,-,\times,\div,\#\},$$

where \(\#\) means decimal concatenation.

Therefore the total number of raw operator patterns is

$$5^8=390625.$$

For example, the pattern

1#2 + 3#4 * 5 - 6#7#8 / 9

collapses to the token list

$$12,\ 34,\ 5,\ 678,\ 9$$

with operator list

$$+,\ \times,\ -,\ \div.$$

So after concatenations are resolved, every pattern becomes a sequence

$$v_0,v_1,\dots,v_{m-1}\in \mathbb Z_{>0}$$

together with operators

$$o_0,o_1,\dots,o_{m-2}\in\{+,-,\times,\div\},$$

where \(1\le m\le 9\).

2. Why Parentheses Lead to Interval Dynamic Programming

Once the token list is fixed, the only remaining freedom is the parenthesization.

Any fully parenthesized binary expression over

$$v_l,v_{l+1},\dots,v_r$$

has a last operation performed at some split position \(k\), where

$$l\le k<r.$$

That last step combines:

1. a fully parenthesized expression on the left interval \([l,k]\),

2. a fully parenthesized expression on the right interval \([k+1,r]\),

3. the fixed operator \(o_k\) between those two intervals.

This is exactly the same structural idea as matrix-chain dynamic programming: every binary tree has a final split.

3. The Interval DP State

For every interval \([l,r]\), define

$$R_{l,r}=\{\text{all exact rational values obtainable from }v_l,\dots,v_r\}.$$

The base case is immediate:

$$R_{i,i}=\{v_i\}.$$

For longer intervals, we split at every possible \(k\):

$$R_{l,r}=\bigcup_{k=l}^{r-1}\{a\;o_k\;b\mid a\in R_{l,k},\ b\in R_{k+1,r}\}.$$

The only forbidden operation is division by zero, so in the division case we keep only pairs with

$$b\ne 0.$$

This recurrence covers every legal parenthesization exactly because every binary expression tree has one unique last split.

4. Why Exact Rational Arithmetic Is Necessary

Intermediate values do not have to be integers. In fact, some reachable positive integers can only be built by passing through fractions.

The official statement gives the example

$$(1/23)\times((4\times 5)-6)\times(78-9)=42.$$

Indeed,

$$((4\times 5)-6)=14,\qquad (78-9)=69,$$

so the expression becomes

$$\frac{1}{23}\times 14\times 69=\frac{966}{23}=42.$$

If we stored only integers, or if we used floating-point approximations, we would lose valid results. Therefore the solver stores every intermediate value as an exact reduced rational number.

5. A Small DP Example

Consider the short token list

$$1,\ 2,\ 3$$

with operators

$$+,\ \times.$$

Then

$$R_{0,0}=\{1\},\qquad R_{1,1}=\{2\},\qquad R_{2,2}=\{3\}.$$

For the interval \([0,1]\), we get

$$R_{0,1}=\{1+2\}=\{3\}.$$

For \([1,2]\),

$$R_{1,2}=\{2\times 3\}=\{6\}.$$

Finally, interval \([0,2]\) has two splits:

$$((1+2)\times 3)=9,$$

$$1+(2\times 3)=7.$$

Hence

$$R_{0,2}=\{7,9\}.$$

This small example shows exactly why a single left-to-right evaluation is not enough: different parenthesizations genuinely create different results.

6. Deduplication Inside Each Interval

Different splits can lead to the same rational number. Also, the same result can appear through different parenthesizations. So every \(R_{l,r}\) must be stored as a set of unique exact values.

The code uses reduced fractions, so for example

$$\frac12=\frac24$$

is recognized automatically as one value, not two.

This local deduplication is important because otherwise the number of intermediate objects would explode much faster.

7. Which Values Contribute to the Final Sum

The DP for one token pattern returns every reachable rational number for the full interval \([0,m-1]\).

A result contributes to the final answer if and only if:

1. its denominator is 1,

2. its numerator is positive.

So the acceptance condition is exactly

$$q=1\qquad\text{and}\qquad p>0$$

for a reduced fraction \(p/q\).

All such integers from all 390625 patterns are inserted into one global set, and only then are they summed. This prevents counting the same reachable integer more than once when it arises from different operator patterns.

8. Why Concatenation Is Handled First

Concatenation is not a binary arithmetic operation on two already-evaluated subexpressions. It is a lexical operation on adjacent digits before the arithmetic tree is built.

That is why the code first converts each base-5 pattern into a token list of integers. Only after this preprocessing step does the interval DP begin.

Mathematically, this separates the problem into two layers:

1. choose how digits are grouped into decimal numbers,

2. choose how those numbers are combined by arithmetic and parentheses.

9. Catalan Structure Without Explicit Tree Generation

If a token pattern has \(m\) numbers, then the number of full binary parenthesizations is the Catalan number

$$C_{m-1}=\frac{1}{m}\binom{2m-2}{m-1}.$$

In the worst case \(m=9\), this gives

$$C_8=1430.$$

The DP does not explicitly generate these 1430 trees one by one. Instead, it memoizes interval results, so every interval is solved once and then reused wherever needed.

10. How the Code Organizes the Global Search

The function collect_for_range processes a block of pattern codes. Each pattern code is read in base 5, which tells the program what to place in each of the 8 gaps.

After tokenization, all_results performs the interval DP and returns all exact reachable rationals for that pattern.

Each thread keeps a local vector of positive integers found in its assigned range. Those vectors are sorted and deduplicated locally, then merged globally at the end.

The final sum uses cpp_int rather than 64-bit integers, because the total sum of all reachable positive integers is too large to assume a small fixed machine type.

11. Why Threading Is Safe Here

The 390625 patterns are completely independent. No pattern needs information from another. So the full search space can be split into disjoint ranges and processed in parallel without changing the mathematical result.

Each worker computes exact reachable values for its own code range, deduplicates locally, and the main thread performs one final union.

How the Code Works

The helper op_from_code converts base-5 digits into one of the five gap choices. The function collect_for_range decodes a pattern, resolves concatenations into a vector of integers values, and builds the matching operator list ops.

The function all_results(values, ops) allocates a 2D DP table where entry \([l][r]\) stores every exact fraction reachable on that token interval. For each split \(k\), it combines every left value with every right value using operator ops[k], skipping division by zero, and deduplicates with a set.

After all threads finish, the main routine merges their integer outputs, removes duplicates once more globally, and sums the remaining values with arbitrary-precision integer arithmetic.

Complexity Analysis

The total number of token patterns is fixed at

$$5^8=390625.$$

For one pattern with \(m\) numeric tokens, interval DP has

$$O(m^2)$$

subintervals and up to

$$O(m)$$

split points per interval. The real cost is dominated by the sizes of the intermediate rational sets and the cartesian products formed when combining them.

Since \(m\le 9\), the token dimension is very small; what makes the problem nontrivial is the huge number of patterns and the need for exact deduplication. Memory usage is proportional to the total number of fractions stored across all DP intervals for one pattern, plus the thread-local and global sets of reachable integers.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=259
  2. Dynamic programming and interval splitting: Wikipedia - Dynamic programming
  3. Matrix-chain style split recurrence: Wikipedia - Matrix chain multiplication
  4. Rational numbers and exact fractions: Wikipedia - Rational number
  5. Catalan numbers: Wikipedia - Catalan number

Problemzusammenfassung

Eine positive ganze Zahl heißt erreichbar, wenn sie aus den Ziffern

1,2,3,4,5,6,7,8,9

in genau dieser Reihenfolge und jeweils genau einmal gebildet werden kann, wobei zwischen zwei benachbarten Ziffern entweder +, -, *, / oder Konkatenation eingesetzt wird. Klammern dürfen beliebig gesetzt werden, ein unärer Minusoperator ist jedoch nicht erlaubt.

Gesucht ist die Summe aller verschiedenen positiven ganzen Zahlen, die sich auf diese Weise exakt erzeugen lassen.

Mathematischer Ansatz

1. Kodierung aller zulässigen Muster

Zwischen den 9 Ziffern gibt es genau 8 Lücken. In jede Lücke kommt eine Wahl aus

$$\{+,-,\times,\div,\#\},$$

wobei \(\#\) die Dezimalkonkatenation bezeichnet.

Damit gibt es insgesamt

$$5^8=390625$$

rohe Muster.

Nach dem Auflösen aller Konkatenationen erhält man eine Zahlenfolge

$$v_0,v_1,\dots,v_{m-1}$$

und eine Operatorkette

$$o_0,o_1,\dots,o_{m-2}\in\{+,-,\times,\div\},$$

wobei \(1\le m\le 9\).

2. Warum Klammern zu einer Intervall-DP führen

Ist die Tokenfolge fest, bleibt nur noch die Klammerung frei. Jede vollständig geklammerte binäre Auswertung auf einem Intervall \([l,r]\) besitzt einen letzten Rechenschritt an einer eindeutigen Split-Position \(k\) mit

$$l\le k<r.$$

Dieser letzte Schritt kombiniert:

1. einen Wert aus dem linken Intervall \([l,k]\),

2. einen Wert aus dem rechten Intervall \([k+1,r]\),

3. den festen Operator \(o_k\) dazwischen.

Genau daraus entsteht die Intervall-DP.

3. Die DP-Definition

Für jedes Intervall definieren wir

$$R_{l,r}=\{\text{alle exakten rationalen Werte aus }v_l,\dots,v_r\}.$$

Die Basis lautet

$$R_{i,i}=\{v_i\}.$$

Für längere Intervalle gilt

$$R_{l,r}=\bigcup_{k=l}^{r-1}\{a\;o_k\;b\mid a\in R_{l,k},\ b\in R_{k+1,r}\}.$$

Im Divisionsfall werden nur Paare mit

$$b\ne 0$$

zugelassen.

4. Warum exakte Brüche nötig sind

Zwischenwerte müssen nicht ganzzahlig sein. Manche erreichbaren positiven ganzen Zahlen entstehen erst über Zwischenbrüche.

Das offizielle Beispiel ist

$$(1/23)\times((4\times 5)-6)\times(78-9)=42.$$

Hier treten also sowohl Konkatenation als auch echte Brüche auf. Deshalb speichert der Solver alle Zwischenwerte als vollständig gekürzte rationale Zahlen und nicht als Gleitkommazahlen.

5. Kleines DP-Beispiel

Betrachte die Tokenfolge

$$1,\ 2,\ 3$$

mit Operatoren

$$+,\ \times.$$

Dann gilt

$$R_{0,0}=\{1\},\qquad R_{1,1}=\{2\},\qquad R_{2,2}=\{3\}.$$

Für \([0,1]\) erhält man

$$R_{0,1}=\{3\},$$

für \([1,2]\) erhält man

$$R_{1,2}=\{6\}.$$

Beim Gesamtintervall \([0,2]\) gibt es zwei Klammerungen:

$$((1+2)\times 3)=9,\qquad 1+(2\times 3)=7.$$

Also

$$R_{0,2}=\{7,9\}.$$

6. Deduplikation innerhalb eines Intervalls

Verschiedene Splits oder verschiedene Klammerungen können denselben rationalen Wert erzeugen. Deshalb muss jedes \(R_{l,r}\) als Menge eindeutiger Werte gespeichert werden.

Da die Brüche gekürzt gespeichert werden, erkennt das Programm etwa

$$\frac12=\frac24$$

automatisch als denselben Wert.

7. Welche Werte am Ende zählen

Ein Ergebnis trägt nur dann zur globalen Summe bei, wenn es ein positiver ganzzahliger Wert ist. Für einen gekürzten Bruch \(p/q\) bedeutet das exakt:

$$q=1\qquad\text{und}\qquad p>0.$$

Alle solchen Werte aus allen 390625 Mustern werden global vereinigt und erst danach einmal summiert.

8. Warum Konkatenation vor der DP abgearbeitet wird

Konkatenation ist keine gewöhnliche binäre Rechenoperation auf bereits ausgewerteten Teilbäumen. Sie ist ein lexikalischer Schritt auf benachbarten Ziffern. Darum löst der Code zuerst alle \(\#\)-Marker auf und baut daraus die Tokenliste auf. Erst danach beginnt die eigentliche arithmetische Intervall-DP.

9. Catalan-Struktur ohne explizite Baumerzeugung

Hat ein Muster \(m\) Zahlen-Tokens, dann ist die Zahl aller vollständigen binären Klammerungen die Catalan-Zahl

$$C_{m-1}=\frac{1}{m}\binom{2m-2}{m-1}.$$

Im schlimmsten Fall \(m=9\) ist das

$$C_8=1430.$$

Die DP erzeugt diese Bäume nicht einzeln, sondern memoisiert Intervallresultate und benutzt sie wieder.

10. Wie der Code die globale Suche organisiert

collect_for_range verarbeitet einen Bereich von Muster-Codes. Jeder Code wird in Basis 5 gelesen und dadurch in die 8 Lückenentscheidungen zerlegt.

Nach der Tokenisierung berechnet all_results per Intervall-DP alle exakten rationalen Werte für dieses Muster.

Jeder Thread sammelt seine lokal gefundenen positiven ganzen Zahlen, sortiert und dedupliziert lokal, und erst am Ende erfolgt die globale Vereinigung. Die Endsumme wird mit cpp_int gebildet, weil die Gesamtantwort bewusst nicht als kleiner 64-Bit-Wert angenommen wird.

Funktionsweise des Codes

op_from_code wandelt Basis-5-Ziffern in Operatoren um. collect_for_range löst daraus Konkatenationen auf und erzeugt die Vektoren values und ops.

all_results(values, ops) baut die 2D-DP-Tabelle auf. Für jedes Intervall und jede Split-Stelle kombiniert die Funktion alle linken und rechten Werte mit dem passenden Operator, überspringt Division durch null und dedupliziert mit einer Menge.

Nach Abschluss aller Threads werden die lokalen Ergebnisvektoren zusammengeführt, global dedupliziert und mit beliebig großer Ganzzahlarithmetik aufsummiert.

Komplexitätsanalyse

Die Zahl der Rohmuster ist fest:

$$5^8=390625.$$

Für ein einzelnes Muster mit \(m\) Tokens besitzt die Intervall-DP

$$O(m^2)$$

Teilintervalle und bis zu

$$O(m)$$

Splitstellen je Intervall. Die eigentliche Laufzeit wird jedoch vor allem durch die Größen der Zwischenmengen rationaler Werte bestimmt. Da \(m\le 9\), ist die Token-Dimension klein; anspruchsvoll ist vor allem die große Zahl von Mustern und die exakte Deduplikation.

Fußnoten und Quellen

  1. Problemseite: https://projecteuler.net/problem=259
  2. Dynamische Programmierung: Wikipedia
  3. Matrix-Chain-Idee: Wikipedia - Matrix chain multiplication
  4. Rationale Zahlen: Wikipedia
  5. Catalan-Zahlen: Wikipedia

Problem Özeti

Bir pozitif tam sayı, aşağıdaki kurallara uyan bir aritmetik ifadeden elde edilebiliyorsa reachable sayılır:

1. Rakamlar 1,2,3,4,5,6,7,8,9 tam bu sırayla ve tam birer kez kullanılmalıdır.

2. Ardışık iki rakam arasına +, -, *, / veya birleştirme konabilir.

3. Parantezler istenildiği gibi yerleştirilebilir.

4. Tekli eksi yasaktır.

Amaç, ulaşılabilen tüm farklı pozitif tam sayıların toplamını bulmaktır.

Matematiksel Yaklaşım

1. Tüm Geçerli Desenleri Kodlamak

9 rakam arasında tam 8 boşluk vardır. Her boşluk için

$$\{+,-,\times,\div,\#\}$$

kümesinden bir seçim yapılır; burada \(\#\) ondalık birleştirme demektir.

Bu yüzden toplam ham desen sayısı

$$5^8=390625$$

olur.

Birleştirmeler çözüldüğünde, her desen şu biçime dönüşür:

$$v_0,v_1,\dots,v_{m-1}\in\mathbb Z_{>0}$$

ve bunların arasındaki işlem listesi

$$o_0,o_1,\dots,o_{m-2}\in\{+,-,\times,\div\}.$$

Burada \(1\le m\le 9\) olur.

2. Neden Parantezleme Interval DP'ye Gidiyor

Token listesi sabitlendiğinde geriye yalnızca parantezleme serbestliği kalır.

\([l,r]\) aralığındaki herhangi bir tam parantezli ifade, son adımında mutlaka bir \(k\) bölme noktasında iki alt ifadeyi birleştirir:

$$l\le k<r.$$

Bu son adımda:

1. soldan \([l,k]\) aralığındaki bir değer,

2. sağdan \([k+1,r]\) aralığındaki bir değer,

3. aradaki sabit operatör \(o_k\)

kullanılır. Bu yüzden doğal yapı interval dynamic programming olur.

3. DP Durumu

Her \([l,r]\) aralığı için

$$R_{l,r}=\{\text{\(v_l,\dots,v_r\) kullanılarak elde edilebilen tüm tam rasyonel değerler}\}$$

tanımlanır.

Başlangıç durumu:

$$R_{i,i}=\{v_i\}.$$

Geçiş:

$$R_{l,r}=\bigcup_{k=l}^{r-1}\{a\;o_k\;b\mid a\in R_{l,k},\ b\in R_{k+1,r}\}.$$

Bölme işleminde yalnızca

$$b\ne 0$$

olan durumlar tutulur.

4. Neden Kesin Kesir Aritmetiği Gerekli

Ara değerlerin tam sayı olması gerekmez. Hatta bazı reachable tam sayılar ancak kesirlerden geçerek elde edilir.

Resmî problemde verilen örnek şudur:

$$(1/23)\times((4\times 5)-6)\times(78-9)=42.$$

Burada hem birleştirme hem de ara kesirler vardır. Dolayısıyla kayan noktalı sayı kullanmak doğru olmaz; her ara değer indirgenmiş rasyonel sayı olarak tutulmalıdır.

5. Küçük Bir DP Örneği

Şu kısa token listesini düşünelim:

$$1,\ 2,\ 3$$

ve işlemler

$$+,\ \times.$$

O zaman

$$R_{0,0}=\{1\},\qquad R_{1,1}=\{2\},\qquad R_{2,2}=\{3\}.$$

\([0,1]\) aralığı için

$$R_{0,1}=\{3\},$$

\([1,2]\) aralığı için

$$R_{1,2}=\{6\}$$

elde edilir.

Toplam aralık \([0,2]\) ise iki farklı son bölmeye sahiptir:

$$((1+2)\times 3)=9,\qquad 1+(2\times 3)=7.$$

Dolayısıyla

$$R_{0,2}=\{7,9\}.$$

Bu örnek, tek bir soldan sağa değerlendirme yerine tüm ikili parantez ağaçlarının neden hesaba katılması gerektiğini gösterir.

6. Her Aralıkta Tekilleştirme Neden Gerekli

Farklı bölme noktaları veya farklı parantezlemeler aynı rasyonel değeri üretebilir. Bu nedenle her \(R_{l,r}\) küme mantığıyla tutulmalıdır.

Kesirler indirgenmiş biçimde saklandığı için örneğin

$$\frac12=\frac24$$

otomatik olarak tek değer kabul edilir.

7. Son Toplama Hangi Değerler Girer

Bir desen için tüm ifade sonuçları bulunduğunda, bir değerin genel cevaba katkı yapması için şunlar gerekir:

1. payda 1 olmalı,

2. pay pozitif olmalı.

Yani indirgenmiş \(p/q\) kesri için koşul tam olarak

$$q=1\qquad\text{ve}\qquad p>0$$

şeklindedir.

Tüm 390625 desenden gelen bu tür tamsayılar tek bir global kümede birleştirilir ve ancak sonra toplanır. Böylece aynı tam sayı farklı desenlerden gelse bile yalnızca bir kez sayılır.

8. Birleştirme Neden Önce Çözülür

Birleştirme, iki hazır alt ifadenin üzerine uygulanan sıradan bir ikili işlem değildir. O, önce komşu rakamları tek bir ondalık sayıya dönüştüren sözdizimsel bir adımdır.

Bu yüzden kod önce \(\#\) işaretlerini çözerek token listesini kurar; asıl aritmetik interval DP bundan sonra başlar.

9. Catalan Yapısı ve Ağaçları Tek Tek Üretmeme

Bir desende \(m\) adet sayı token'ı varsa, tam ikili parantezleme sayısı Catalan sayısıdır:

$$C_{m-1}=\frac{1}{m}\binom{2m-2}{m-1}.$$

En kötü durumda \(m=9\) için

$$C_8=1430$$

olur.

DP, bu 1430 ağacı tek tek üretmez; aynı interval sonuçlarını belleğe alıp tekrar kullanır.

10. Kodun Küresel Aramayı Nasıl Düzenlediği

collect_for_range belli bir kod aralığını işler. Her kod taban-5 olarak çözülür ve 8 boşluğun her biri için hangi seçim yapıldığı bulunur.

Tokenizasyon sonrası all_results çağrılır ve bu desen için ulaşılabilen tüm tam rasyonel değerler hesaplanır.

Her iş parçacığı kendi aralığından bulduğu pozitif tamsayıları yerel vektörde toplar, yerel sıralama ve tekilleştirme yapar. Ana iş parçacığı ise en sonunda bunları birleştirir.

Nihai toplam için cpp_int kullanılır; çünkü reachable tamsayıların toplamı küçük bir 64-bit türüne güvenilecek kadar sınırlı kabul edilmez.

11. Çok İş Parçacıklılık Neden Güvenlidir

390625 desen birbirinden tamamen bağımsızdır. Bir desenin sonucu başka bir desene bağlı değildir. Bu yüzden aralıklar güvenli biçimde parçalara ayrılıp paralel işlenebilir. Son matematiksel sonuç, yalnızca en sonda yapılan birleşim ve tekilleştirmedir.

Kod Nasıl Çalışıyor

op_from_code taban-5 rakamlarını operatörlere çevirir. collect_for_range bu desenleri okuyup önce birleştirmeleri çözer, sonra values ve ops listelerini üretir.

all_results(values, ops), \([l][r]\) girişlerinde o intervalde elde edilebilen tüm kesirleri tutan bir 2B DP tablosu kurar. Her bölme noktası için soldaki ve sağdaki tüm sonuçlar uygun operatörle birleştirilir, sıfıra bölme atlanır ve sonuçlar kümeyle tekilleştirilir.

Tüm iş parçacıkları bittikten sonra ana yordam yerel sonuçları birleştirir, global tekilleştirme yapar ve geriye kalan pozitif tamsayıları büyük tam sayı aritmetiğiyle toplar.

Karmaşıklık Analizi

Toplam ham desen sayısı sabittir:

$$5^8=390625.$$

Bir desen için, \(m\) token üzerinde interval DP'nin

$$O(m^2)$$

adet alt aralığı ve aralık başına en fazla

$$O(m)$$

bölme noktası vardır. Gerçek maliyet ise esas olarak ara rasyonel kümelerin boyutlarına ve bunların kartezyen çarpımlarına bağlıdır.

\(m\le 9\) olduğu için token boyutu küçüktür; asıl zorluk çok sayıdaki desen ve tam doğrulukla tekilleştirme yapmaktır. Bellek tüketimi, tek bir desen için tüm interval kümelerinde saklanan kesir sayısına ve thread-local / global sonuç kümelerine bağlıdır.

Dipnotlar ve Kaynaklar

  1. Problem sayfası: https://projecteuler.net/problem=259
  2. Dinamik programlama: Wikipedia
  3. Matrix-chain tipi bölme fikri: Wikipedia - Matrix chain multiplication
  4. Rasyonel sayılar: Wikipedia
  5. Catalan sayıları: Wikipedia

Resumen del Problema

Un entero positivo se llama alcanzable si puede obtenerse a partir de los digitos

1,2,3,4,5,6,7,8,9

usados exactamente una vez y en ese mismo orden, bajo estas reglas:

1. En cada hueco se puede poner +, -, *, / o concatenacion.

2. Los parentesis pueden colocarse libremente.

3. No se permite menos unario.

La meta es sumar todos los enteros positivos distintos que sean alcanzables exactamente.

Enfoque Matematico

1. Codificar todos los patrones

Hay 8 huecos entre 9 digitos. En cada uno elegimos un simbolo de

$$\{+,-,\times,\div,\#\},$$

donde \(\#\) significa concatenacion decimal.

Por tanto, el numero total de patrones brutos es

$$5^8=390625.$$

Al resolver las concatenaciones, cada patron se convierte en una lista de numeros

$$v_0,v_1,\dots,v_{m-1}$$

y una lista de operadores

$$o_0,o_1,\dots,o_{m-2}\in\{+,-,\times,\div\},$$

con \(1\le m\le 9\).

2. Por que los parentesis llevan a DP por intervalos

Una vez fijada la lista de tokens, la unica libertad restante es la parentizacion.

Cualquier expresion binaria completamente parentizada sobre el intervalo \([l,r]\) tiene una ultima operacion en algun punto de corte \(k\) con

$$l\le k<r.$$

Esa ultima operacion combina:

1. un resultado del intervalo izquierdo \([l,k]\),

2. un resultado del intervalo derecho \([k+1,r]\),

3. el operador fijo \(o_k\).

3. El estado de la DP

Definimos

$$R_{l,r}=\{\text{todos los valores racionales exactos obtenibles con }v_l,\dots,v_r\}.$$

Base:

$$R_{i,i}=\{v_i\}.$$

Transicion:

$$R_{l,r}=\bigcup_{k=l}^{r-1}\{a\;o_k\;b\mid a\in R_{l,k},\ b\in R_{k+1,r}\}.$$

En el caso de division solo se aceptan parejas con

$$b\ne 0.$$

4. Por que hacen falta fracciones exactas

Los valores intermedios no tienen por que ser enteros. Algunas soluciones enteras pasan necesariamente por fracciones.

El ejemplo oficial es

$$(1/23)\times((4\times 5)-6)\times(78-9)=42.$$

Por eso el algoritmo guarda cada valor intermedio como racional exacto reducido y no como numero en coma flotante.

5. Un ejemplo pequeno de la DP

Tomemos la lista de tokens

$$1,\ 2,\ 3$$

con operadores

$$+,\ \times.$$

Entonces

$$R_{0,0}=\{1\},\qquad R_{1,1}=\{2\},\qquad R_{2,2}=\{3\}.$$

Para \([0,1]\),

$$R_{0,1}=\{3\},$$

y para \([1,2]\),

$$R_{1,2}=\{6\}.$$

En el intervalo completo aparecen dos parentizaciones:

$$((1+2)\times 3)=9,\qquad 1+(2\times 3)=7.$$

Por tanto

$$R_{0,2}=\{7,9\}.$$

6. Eliminacion de duplicados dentro de cada intervalo

Distintos cortes pueden llevar al mismo valor racional, y distintas parentizaciones tambien. Por eso cada \(R_{l,r}\) debe almacenarse como conjunto de valores unicos.

Como las fracciones se guardan reducidas, por ejemplo

$$\frac12=\frac24$$

se reconoce automaticamente como el mismo valor.

7. Que valores contribuyen a la suma final

Un resultado cuenta solo si es un entero positivo. Para una fraccion reducida \(p/q\), eso equivale a

$$q=1\qquad\text{y}\qquad p>0.$$

Todos esos enteros, procedentes de los 390625 patrones, se unen en un conjunto global antes de sumarse, de modo que cada entero alcanzable se cuenta una sola vez.

8. Por que la concatenacion se resuelve primero

La concatenacion no es una operacion aritmetica binaria sobre dos subexpresiones ya evaluadas. Es un paso sintactico sobre digitos consecutivos. Por eso el programa primero agrupa digitos en numeros decimales y solo despues ejecuta la DP aritmetica.

9. Estructura de Catalan sin generar arboles explicitamente

Si un patron tiene \(m\) tokens numericos, el numero de parentizaciones binarias completas es el numero de Catalan

$$C_{m-1}=\frac{1}{m}\binom{2m-2}{m-1}.$$

En el peor caso \(m=9\), tenemos

$$C_8=1430.$$

La DP evita generar esos 1430 arboles uno por uno porque memoriza los resultados por intervalo.

10. Como organiza el codigo la busqueda global

collect_for_range procesa un bloque de codigos de patrones. Cada codigo se interpreta en base 5 y de ahi se obtienen las 8 decisiones de hueco.

Tras tokenizar, all_results calcula todos los racionales exactos alcanzables para ese patron.

Cada hilo mantiene un vector local con los enteros positivos encontrados en su rango, lo ordena y lo depura localmente. Al final el hilo principal hace la union global. La suma final se almacena en cpp_int.

Como Funciona el Codigo

op_from_code traduce digitos en base 5 a operadores. collect_for_range resuelve primero las concatenaciones y construye los vectores values y ops.

all_results(values, ops) crea la tabla DP por intervalos. Para cada corte \(k\), combina todos los resultados de la izquierda y de la derecha con el operador ops[k], omite la division por cero y elimina duplicados con un conjunto.

Cuando terminan todos los hilos, el programa fusiona sus salidas, vuelve a eliminar duplicados a nivel global y suma los enteros restantes con aritmetica de precision arbitraria.

Analisis de Complejidad

El numero total de patrones es fijo:

$$5^8=390625.$$

Para un patron con \(m\) tokens, la DP por intervalos tiene

$$O(m^2)$$

subproblemas y hasta

$$O(m)$$

puntos de corte por subproblema. El coste real viene dominado por el tamano de los conjuntos intermedios de racionales y por sus combinaciones. Como \(m\le 9\), la dimension estructural es pequena; la dificultad real esta en los muchisimos patrones y en la deduplicacion exacta.

Notas y Referencias

  1. Pagina del problema: https://projecteuler.net/problem=259
  2. Programacion dinamica: Wikipedia
  3. Idea tipo matrix-chain: Wikipedia - Matrix chain multiplication
  4. Numeros racionales: Wikipedia
  5. Numeros de Catalan: Wikipedia

问题概述

如果一个正整数可以由数字

1,2,3,4,5,6,7,8,9

按原顺序、各用一次,通过如下规则构造出来,就称它是 reachable:

1. 在相邻数字之间可以放 +-*/ 或十进制拼接。

2. 括号可以任意放置。

3. 不允许一元负号。

目标是把所有不同的可达正整数求并集后再求和。

数学方法

1. 如何编码全部表达式模式

9 个数字之间有 8 个空隙。每个空隙都从

$$\{+,-,\times,\div,\#\}$$

中选一个符号,其中 \(\#\) 表示十进制拼接。

因此总模式数为

$$5^8=390625.$$

先处理完拼接之后,每个模式都会变成一个数列

$$v_0,v_1,\dots,v_{m-1}$$

和一个运算符序列

$$o_0,o_1,\dots,o_{m-2}\in\{+,-,\times,\div\},$$

其中 \(1\le m\le 9\)。

2. 为什么括号问题会变成区间 DP

一旦 token 序列固定,唯一剩下的自由度就是括号结构。

任意一个作用在区间 \([l,r]\) 上的完全二叉表达式,都有一个最后执行的运算,它发生在某个切分点 \(k\) 上,其中

$$l\le k<r.$$

这个最后一步会把:

1. 左区间 \([l,k]\) 的某个值,

2. 右区间 \([k+1,r]\) 的某个值,

3. 中间固定的运算符 \(o_k\)

组合起来。这正是区间 DP 的标准结构。

3. DP 状态定义

对每个区间 \([l,r]\),定义

$$R_{l,r}=\{\text{由 }v_l,\dots,v_r\text{ 能精确得到的全部有理数值}\}.$$

边界条件为

$$R_{i,i}=\{v_i\}.$$

转移为

$$R_{l,r}=\bigcup_{k=l}^{r-1}\{a\;o_k\;b\mid a\in R_{l,k},\ b\in R_{k+1,r}\}.$$

在除法情形下,只保留

$$b\ne 0$$

的组合。

4. 为什么必须使用精确分数

中间结果不一定是整数。有些最终的正整数只能通过中间分数得到。

官方给出的例子是

$$(1/23)\times((4\times 5)-6)\times(78-9)=42.$$

因此算法不能只保留整数,也不能使用浮点近似,而必须把每个中间值存成约分后的精确有理数。

5. 一个小型 DP 例子

考虑 token 序列

$$1,\ 2,\ 3$$

以及运算符

$$+,\ \times.$$

$$R_{0,0}=\{1\},\qquad R_{1,1}=\{2\},\qquad R_{2,2}=\{3\}.$$

对区间 \([0,1]\),有

$$R_{0,1}=\{3\},$$

对区间 \([1,2]\),有

$$R_{1,2}=\{6\}.$$

而整个区间 \([0,2]\) 有两种最后切分方式:

$$((1+2)\times 3)=9,\qquad 1+(2\times 3)=7.$$

所以

$$R_{0,2}=\{7,9\}.$$

6. 为什么每个区间都要去重

不同切分点、不同括号结构可能得到同一个有理数。因此每个 \(R_{l,r}\) 都必须是“唯一值集合”。

由于分数按最简形式保存,所以

$$\frac12=\frac24$$

会自动视为同一个值。

7. 最后哪些值会进入答案

对一个完整模式来说,最终区间 \([0,m-1]\) 的结果中,只有满足以下条件的值才会贡献到总和:

1. 分母等于 1;

2. 分子为正。

也就是对最简分数 \(p/q\),条件正是

$$q=1\qquad\text{且}\qquad p>0.$$

来自全部 390625 个模式的这些正整数会被放入一个全局集合,最终只加一次。

8. 为什么要先处理拼接

拼接不是“两个已算好的子表达式之间的普通二元运算”,而是先把相邻数字词法上合并成十进制整数。因此代码必须先消化所有 \(\#\),得到 token 列表,然后才开始真正的算术区间 DP。

9. Catalan 结构与不显式生成语法树

如果某个模式产生了 \(m\) 个数 token,那么其完整二叉括号结构数量就是 Catalan 数

$$C_{m-1}=\frac{1}{m}\binom{2m-2}{m-1}.$$

最坏情况下 \(m=9\),于是

$$C_8=1430.$$

代码并不把这 1430 棵树逐一生成,而是通过区间 DP 复用子区间结果。

10. 代码如何组织全局搜索

collect_for_range 负责处理一段模式编号。每个编号按五进制展开,就得到 8 个空隙各自的选择。

完成 token 化之后,all_results 会求出该模式对应的全部精确有理数结果。

每个线程把自己范围内得到的正整数收集到局部向量中,先在本地排序去重,再由主线程做最终并集。总和使用 cpp_int 保存,以避免固定 64 位整数溢出。

代码如何工作

op_from_code 把五进制数字映射为 5 种空隙选择。collect_for_range 先解析这些选择,解决拼接,再构造 valuesops 两个数组。

all_results(values, ops) 建立二维区间 DP 表。对每个切分点 \(k\),它会把左区间和右区间的所有结果按 ops[k] 组合,跳过除零情况,并用集合去重。

所有线程结束后,主程序合并局部结果、再次全局去重,并用大整数把剩余正整数求和。

复杂度分析

总模式数固定为

$$5^8=390625.$$

对一个含 \(m\) 个 token 的模式,区间 DP 有

$$O(m^2)$$

个子区间,每个子区间最多有

$$O(m)$$

个切分点。真正的开销主要来自中间有理数集合的大小以及左右集合做笛卡尔组合时的成本。

由于 \(m\le 9\),结构尺寸本身不大;困难主要来自模式数量极多以及必须做精确去重。内存复杂度同样由这些中间集合和最终结果集合的大小主导。

参考资料

  1. 题目页面: https://projecteuler.net/problem=259
  2. 动态规划: Wikipedia
  3. 区间切分思想: Wikipedia - Matrix chain multiplication
  4. 有理数: Wikipedia
  5. Catalan 数: Wikipedia

Краткое описание

Положительное целое число называется достижимым, если его можно получить из цифр

1,2,3,4,5,6,7,8,9

в этом же порядке и ровно по одному разу, соблюдая правила:

1. между соседними цифрами можно поставить +, -, *, / или конкатенацию;

2. скобки разрешены в любом виде;

3. унарный минус запрещен.

Нужно найти сумму всех различных положительных целых чисел, достижимых точно.

Математический подход

1. Кодирование всех шаблонов

Между 9 цифрами есть ровно 8 промежутков. В каждый промежуток помещается один символ из

$$\{+,-,\times,\div,\#\},$$

где \(\#\) означает десятичную конкатенацию.

Итак, число сырых шаблонов равно

$$5^8=390625.$$

После выполнения всех конкатенаций каждый шаблон превращается в список чисел

$$v_0,v_1,\dots,v_{m-1}$$

и список операторов

$$o_0,o_1,\dots,o_{m-2}\in\{+,-,\times,\div\},$$

где \(1\le m\le 9\).

2. Почему скобки приводят к интервальному DP

Когда список токенов уже фиксирован, остается только свобода расстановки скобок.

Любое полностью скобочное бинарное выражение на интервале \([l,r]\) имеет последнюю операцию в некоторой точке разреза \(k\), где

$$l\le k<r.$$

Эта последняя операция объединяет:

1. значение из левого интервала \([l,k]\),

2. значение из правого интервала \([k+1,r]\),

3. фиксированный оператор \(o_k\).

3. Состояние DP

Для каждого интервала определим

$$R_{l,r}=\{\text{все точные рациональные значения, достижимые из }v_l,\dots,v_r\}.$$

База:

$$R_{i,i}=\{v_i\}.$$

Переход:

$$R_{l,r}=\bigcup_{k=l}^{r-1}\{a\;o_k\;b\mid a\in R_{l,k},\ b\in R_{k+1,r}\}.$$

В случае деления оставляются только пары с

$$b\ne 0.$$

4. Почему нужны точные дроби

Промежуточные значения вовсе не обязаны быть целыми. Некоторые итоговые положительные целые числа возникают только через промежуточные дроби.

Официальный пример:

$$(1/23)\times((4\times 5)-6)\times(78-9)=42.$$

Поэтому алгоритм обязан хранить промежуточные значения как точные сокращенные рациональные числа, а не как числа с плавающей точкой.

5. Небольшой пример работы DP

Рассмотрим токены

$$1,\ 2,\ 3$$

с операторами

$$+,\ \times.$$

Тогда

$$R_{0,0}=\{1\},\qquad R_{1,1}=\{2\},\qquad R_{2,2}=\{3\}.$$

Для \([0,1]\) имеем

$$R_{0,1}=\{3\},$$

для \([1,2]\)

$$R_{1,2}=\{6\}.$$

На полном интервале \([0,2]\) существуют две скобочные структуры:

$$((1+2)\times 3)=9,\qquad 1+(2\times 3)=7.$$

Поэтому

$$R_{0,2}=\{7,9\}.$$

6. Удаление дублей внутри интервала

Разные разрезы и разные скобочные структуры могут приводить к одному и тому же рациональному числу. Поэтому каждое множество \(R_{l,r}\) должно хранить только уникальные значения.

Поскольку дроби сокращаются, например

$$\frac12=\frac24$$

автоматически распознается как один и тот же результат.

7. Какие значения входят в итоговую сумму

Для сокращенной дроби \(p/q\) результат учитывается тогда и только тогда, когда

$$q=1\qquad\text{и}\qquad p>0.$$

То есть берутся только положительные целые значения. Все такие значения из всех 390625 шаблонов объединяются в одно глобальное множество и суммируются один раз.

8. Почему конкатенация обрабатывается заранее

Конкатенация не является обычной бинарной арифметической операцией над уже вычисленными поддеревьями. Это синтаксическая операция над соседними цифрами. Поэтому код сначала строит числовые токены, а уже потом запускает интервальную арифметическую DP.

9. Структура Каталана без явной генерации деревьев

Если в шаблоне получилось \(m\) числовых токенов, то число полных бинарных скобочных структур равно числу Каталана

$$C_{m-1}=\frac{1}{m}\binom{2m-2}{m-1}.$$

В худшем случае \(m=9\), и тогда

$$C_8=1430.$$

DP не строит все 1430 деревьев по отдельности, а переиспользует результаты подинтервалов.

10. Как код организует глобальный перебор

collect_for_range обрабатывает диапазон кодов шаблонов. Каждый код читается в системе счисления по основанию 5, что определяет 8 выборов между цифрами.

После токенизации функция all_results вычисляет все точные рациональные результаты для данного шаблона.

Каждый поток собирает свои положительные целые числа локально, сортирует и убирает дубли. Затем главный поток выполняет финальное объединение. Для суммы используется cpp_int.

Как работает код

op_from_code переводит цифру в базе 5 в один из пяти вариантов для промежутка. collect_for_range сперва разрешает конкатенации и строит списки values и ops.

all_results(values, ops) строит двумерную таблицу DP по интервалам. Для каждого разреза \(k\) она комбинирует все левые и правые значения через оператор ops[k], пропускает деление на ноль и убирает повторы с помощью множества.

После завершения всех потоков главный код сливает локальные результаты, снова устраняет глобальные дубли и суммирует итоговые положительные целые числа с использованием длинной арифметики.

Сложность

Число шаблонов фиксировано:

$$5^8=390625.$$

Для одного шаблона с \(m\) токенами интервальная DP имеет

$$O(m^2)$$

подинтервалов и до

$$O(m)$$

точек разбиения. Основная стоимость определяется размерами промежуточных множеств рациональных значений и их попарными комбинациями. Так как \(m\le 9\), структурный размер мал, а основная трудность - огромное число шаблонов и точная дедупликация.

Ссылки

  1. Страница задачи: https://projecteuler.net/problem=259
  2. Динамическое программирование: Wikipedia
  3. Идея matrix-chain: Wikipedia - Matrix chain multiplication
  4. Рациональные числа: Wikipedia
  5. Числа Каталана: Wikipedia

ملخص المسألة

يُقال عن عدد صحيح موجب إنه reachable إذا أمكن الحصول عليه من الأرقام

1,2,3,4,5,6,7,8,9

مع استعمالها مرة واحدة لكل رقم وبالترتيب نفسه دائمًا، وفق القواعد التالية:

1. بين كل رقمين متجاورين يمكن وضع + أو - أو * أو / أو دمج عشري.

2. يمكن وضع الأقواس بأي شكل.

3. لا يُسمح بالناقص الأحادي.

المطلوب هو مجموع كل القيم الصحيحة الموجبة المختلفة التي يمكن الوصول إليها بدقة.

المنهج الرياضي

1. ترميز جميع الأنماط الممكنة

بين 9 أرقام توجد 8 فجوات. في كل فجوة نختار رمزًا من

$$\{+,-,\times,\div,\#\},$$

حيث ترمز \(\#\) إلى الدمج العشري.

إذًا فإن عدد الأنماط الخام يساوي

$$5^8=390625.$$

بعد حل جميع عمليات الدمج يتحول كل نمط إلى قائمة أعداد

$$v_0,v_1,\dots,v_{m-1}$$

وقائمة عمليات

$$o_0,o_1,\dots,o_{m-2}\in\{+,-,\times,\div\},$$

حيث \(1\le m\le 9\).

2. لماذا تقود الأقواس إلى برمجة ديناميكية على المجالات

بعد تثبيت قائمة الرموز العددية، لا يبقى إلا حرية اختيار شكل الأقواس.

أي تعبير ثنائي كامل على المجال \([l,r]\) له عملية أخيرة واحدة تقع عند نقطة قطع \(k\) تحقق

$$l\le k<r.$$

وتقوم هذه العملية الأخيرة بدمج:

1. قيمة من المجال الأيسر \([l,k]\)،

2. قيمة من المجال الأيمن \([k+1,r]\)،

3. المعامل الثابت \(o_k\) بينهما.

3. تعريف حالة البرمجة الديناميكية

لكل مجال \([l,r]\) نعرّف المجموعة \(R_{l,r}\) على أنها جميع القيم النسبية الدقيقة الممكنة الناتجة من \(v_l,\dots,v_r\).

حالة البداية هي

$$R_{i,i}=\{v_i\}.$$

أما الانتقال فهو

$$R_{l,r}=\bigcup_{k=l}^{r-1}\{a\;o_k\;b\mid a\in R_{l,k},\ b\in R_{k+1,r}\}.$$

وفي حالة القسمة لا نسمح إلا بالحالات التي فيها

$$b\ne 0.$$

4. لماذا نحتاج إلى كسور دقيقة

القيم الوسيطة لا يلزم أن تكون أعدادًا صحيحة. بل إن بعض القيم الصحيحة النهائية لا يمكن الوصول إليها إلا عبر كسور وسيطة.

المثال الرسمي هو

$$(1/23)\times((4\times 5)-6)\times(78-9)=42.$$

لهذا السبب لا يكفي الاحتفاظ بالأعداد الصحيحة فقط، ولا يجوز استخدام التقريب العشري؛ بل يجب تخزين كل قيمة وسيطة على صورة كسر مختزل بدقة تامة.

5. مثال صغير على البرمجة الديناميكية

لنأخذ قائمة الأعداد

$$1,\ 2,\ 3$$

ومعاملَي العمليات

$$+,\ \times.$$

عندئذٍ

$$R_{0,0}=\{1\},\qquad R_{1,1}=\{2\},\qquad R_{2,2}=\{3\}.$$

وبالنسبة إلى \([0,1]\) نحصل على

$$R_{0,1}=\{3\},$$

وبالنسبة إلى \([1,2]\) نحصل على

$$R_{1,2}=\{6\}.$$

أما المجال الكامل \([0,2]\) فيعطي شكلين مختلفين للأقواس:

$$((1+2)\times 3)=9,\qquad 1+(2\times 3)=7.$$

لذلك

$$R_{0,2}=\{7,9\}.$$

6. لماذا نحتاج إلى إزالة التكرارات داخل كل مجال

قد تؤدي نقاط القطع المختلفة أو أشكال الأقواس المختلفة إلى القيمة النسبية نفسها. لذلك يجب أن يُخزن كل \(R_{l,r}\) بوصفه مجموعة قيم فريدة.

وبما أن الكسور تحفظ في صورة مختزلة، فإن

$$\frac12=\frac24$$

يُنظر إليهما تلقائيًا على أنهما القيمة نفسها.

7. ما القيم التي تدخل في المجموع النهائي

لكي تدخل قيمة ما في الجواب النهائي، يجب أن تكون عددًا صحيحًا موجبًا. وهذا يعني بالنسبة إلى الكسر المختزل \(p/q\) أن الشرط هو \(q=1\) و\(p>0\).

كل هذه القيم من جميع الأنماط 390625 تُجمع أولًا في مجموعة عامة واحدة، ثم تُحسب مرة واحدة فقط.

8. لماذا يُحل الدمج أولًا

الدمج ليس عملية حسابية ثنائية عادية على تعبيرين جاهزين، بل هو خطوة تركيبية على الأرقام المتجاورة قبل بناء شجرة التعبير. لذلك يقوم الكود أولًا بتحويل سلاسل الأرقام المدموجة إلى أعداد عشرية، وبعد ذلك فقط يبدأ الـ interval DP الحسابي.

9. بنية Catalan من دون توليد الأشجار صراحة

إذا احتوى نمط ما على \(m\) رموز عددية، فإن عدد جميع أشكال الأقواس الثنائية الكاملة هو عدد Catalan

$$C_{m-1}=\frac{1}{m}\binom{2m-2}{m-1}.$$

وفي أسوأ حالة حين \(m=9\)، نحصل على

$$C_8=1430.$$

لكن البرمجة الديناميكية لا تولد هذه الأشجار 1430 واحدةً واحدة، بل تعيد استخدام نتائج المجالات الفرعية.

10. كيف ينظم الكود البحث العام

تعالج الدالة collect_for_range مجالًا من أكواد الأنماط. ويُقرأ كل كود على أساس 5 للحصول على الاختيارات الثمانية بين الأرقام.

بعد التقطيع إلى أعداد وعمليات، تحسب all_results كل القيم النسبية الدقيقة الممكنة لذلك النمط.

كل خيط يجمع الأعداد الصحيحة الموجبة التي وجدها في متجه محلي، ويرتبها ويزيل تكرارها محليًا، ثم تنفذ الخيط الرئيسي عملية الاتحاد النهائية. ويُستخدم cpp_int لتخزين المجموع النهائي.

كيف يعمل الكود

تحول op_from_code الرقم في النظام الخماسي إلى أحد خيارات الفجوة الخمسة. ثم تقوم collect_for_range بحل الدمج أولًا، وبعد ذلك تبني القائمتين values وops.

أما all_results(values, ops) فتبني جدول DP ثنائي الأبعاد على المجالات. ولكل نقطة قطع \(k\) تجمع كل القيم اليسرى مع كل القيم اليمنى باستخدام المعامل ops[k]، وتتجاوز القسمة على صفر، وتزيل التكرارات عبر مجموعة.

وبعد انتهاء جميع الخيوط، يدمج البرنامج النتائج المحلية، ويزيل التكرارات عالميًا مرة أخرى، ثم يجمع الأعداد الصحيحة الموجبة المتبقية باستعمال حساب صحيح كبير.

تحليل التعقيد

عدد الأنماط ثابت ويساوي

$$5^8=390625.$$

بالنسبة إلى نمط واحد يحوي \(m\) رموزًا عددية، فإن برمجة المجالات الديناميكية تملك

$$O(m^2)$$

مجالات فرعية، ولكل مجال حتى

$$O(m)$$

نقطة قطع. أما الكلفة الحقيقية فتتحكم فيها أحجام مجموعات الكسور الوسيطة وحجوم الضربات الديكارتية عند دمجها. وبما أن \(m\le 9\)، فالحجم البنيوي صغير، لكن عدد الأنماط الكبير وإزالة التكرارات بدقة هما مصدر الصعوبة الفعلية.

مراجع

  1. صفحة المسألة: https://projecteuler.net/problem=259
  2. البرمجة الديناميكية: Wikipedia
  3. فكرة matrix-chain: Wikipedia - Matrix chain multiplication
  4. الأعداد النسبية: Wikipedia
  5. أعداد Catalan: Wikipedia - Catalan number