We consider all lists of strictly increasing primes whose sum is a target \(N\). These lists are sorted in lexicographic order, and the required list is the median list. When the number of lists is even, the last list is ignored first; equivalently, if there are \(M\) lists, the required one has one-based rank
$$r=\left\lfloor\frac{M+1}{2}\right\rfloor.$$
For \(N=20\), the four lists are \((2,5,13)\), \((2,7,11)\), \((3,17)\), and \((7,13)\). Since \(M=4\), the effective median rank is \(2\), giving \((2,7,11)\). The actual problem asks for \(N=2026\), and only the last nine digits of the product of the primes in the median list are needed.
Because every list is strictly increasing, each valid list is exactly a subset of the primes not exceeding \(N\), written in increasing order, whose elements sum to \(N\). If
$$p_0 \lt p_1 \lt \cdots \lt p_{m-1}$$
are the primes at most \(N\), the problem is not to enumerate every subset, but to count enough subsets to jump directly to the median in lexicographic order.
The strict increase is important: after choosing \(p_i\), every later prime in the same list must come from \(p_{i+1},p_{i+2},\dots\). This creates a natural suffix dynamic program.
Define
$$C(i,s)=\#\left\{A\subseteq\{p_i,p_{i+1},\dots,p_{m-1}\}:\sum_{p\in A}p=s\right\}.$$
The boundary condition is
$$C(m,0)=1,\qquad C(m,s)=0\quad(s\gt0).$$
For \(i\lt m\), either \(p_i\) is skipped or it is used. Therefore
$$C(i,s)=C(i+1,s)+ \begin{cases} C(i+1,s-p_i), & s\ge p_i,\\ 0, & s\lt p_i. \end{cases}$$
This is the subset-sum recurrence, but the table is used as a ranking oracle rather than just as a yes/no feasibility test. The total number of prime lists is \(M=C(0,N)\). These counts can be large, so the implementations use arbitrary-precision integers for the DP table.
In lexicographic order, all lists whose first element is \(p_a\) appear before all lists whose first element is \(p_b\) whenever \(p_a\lt p_b\). If we try a candidate first prime \(p_i\), the number of lists beginning with that prime is exactly
$$C(i+1,N-p_i),$$
because the remaining entries must be chosen from strictly larger primes and must sum to \(N-p_i\). Thus each candidate first prime forms one contiguous lexicographic block.
The same idea applies after a prefix has already been fixed. If the current prefix ends at index \(i\), the next candidate \(p_j\) contributes a block of size
$$C(j+1,R-p_j).$$
This block size tells us whether the desired rank lies inside that block or after it.
Set \(r=\lfloor(M+1)/2\rfloor\). Start with remaining sum \(N\) and the first allowable prime index \(0\). Scan candidate primes in increasing order. For a candidate \(p_i\), compute
$$B_i=C(i+1,R-p_i).$$
If \(r>B_i\), the whole block beginning with \(p_i\) is before the median, so subtract it:
$$r\leftarrow r-B_i.$$
If \(r\le B_i\), the median list begins, or continues, with \(p_i\). Append \(p_i\), decrease the remaining sum by \(p_i\), and continue with candidates after \(i\). When the remaining sum becomes \(0\), the list has been reconstructed without enumerating all lists.
The DP gives \(C(0,20)=4\), so \(r=\lfloor(4+1)/2\rfloor=2\). The first candidate \(2\) has
$$C(1,18)=2,$$
corresponding to \((2,5,13)\) and \((2,7,11)\). Since \(r=2\) lies inside this block, the first element is \(2\).
Now the remaining sum is \(18\). Candidate \(3\) has no valid completion, candidate \(5\) has one completion \((13)\), and candidate \(7\) has one completion \((11)\). After skipping the block for \(5\), the rank becomes \(1\), so \(7\) is selected. The final remaining sum is \(11\), forcing the last prime \(11\). Hence the median list is \((2,7,11)\).
primes_up_to builds the prime list by a sieve. build_dp fills the suffix table \(C(i,s)\) from the last prime backward, using arbitrary-precision counts because the number of prime subsets can exceed fixed-width integer ranges.
kth_prime_list performs the lexicographic unranking. For each candidate prime it asks the DP table how many valid completions exist. Entire blocks are skipped by subtracting their sizes from the rank; the first block containing the rank determines the next prime in the answer.
median_prime_list converts the total count into the median rank \((M+1)//2\). Finally product_mod multiplies the selected primes modulo \(10^9\), which is enough because only the last nine digits are requested.
The checkpoint suite explicitly checks the \(N=20\) example and brute-forces every target from \(2\) through \(60\), verifying that the DP count, first rank, median rank, and last rank all match direct enumeration.
Let \(m=\pi(N)\), the number of primes at most \(N\). The DP table has \((m+1)(N+1)\) entries and is filled in \(O(mN)\) arithmetic operations. The unranking pass scans primes at each selected position, bounded by \(O(mL)\), where \(L\) is the length of the median list; this is dominated by the DP for the given target.
The memory usage is \(O(mN)\) arbitrary-precision integers. For \(N=2026\), \(m=306\), so the table is small in practical terms.
Wir betrachten alle Listen streng wachsender Primzahlen, deren Summe ein Zielwert \(N\) ist. Diese Listen werden lexikographisch sortiert, und gesucht ist die Median-Liste. Gibt es eine gerade Anzahl von Listen, wird zuerst die letzte Liste verworfen. Hat man also \(M\) Listen, dann ist der gesuchte einbasierte Rang
$$r=\left\lfloor\frac{M+1}{2}\right\rfloor.$$
Für \(N=20\) sind die vier Listen \((2,5,13)\), \((2,7,11)\), \((3,17)\) und \((7,13)\). Wegen \(M=4\) ist der wirksame Medianrang \(2\), also \((2,7,11)\). In der eigentlichen Aufgabe gilt \(N=2026\), und verlangt werden nur die letzten neun Ziffern des Produkts der Primzahlen in der Median-Liste.
Da jede Liste streng wächst, ist jede gültige Liste genau eine Teilmenge der Primzahlen höchstens \(N\), in aufsteigender Reihenfolge geschrieben, deren Summe \(N\) ergibt. Sind
$$p_0 \lt p_1 \lt \cdots \lt p_{m-1}$$
die Primzahlen bis \(N\), dann sollen nicht alle Teilmengen erzeugt werden. Stattdessen zählen wir genug Teilmengen, um direkt zum Median in lexikographischer Ordnung zu springen.
Die strenge Monotonie ist der entscheidende Punkt: Nach der Wahl von \(p_i\) dürfen spätere Einträge nur noch aus \(p_{i+1},p_{i+2},\dots\) stammen. Dadurch entsteht eine natürliche Suffix-DP.
Definiere
$$C(i,s)=\#\left\{A\subseteq\{p_i,p_{i+1},\dots,p_{m-1}\}:\sum_{p\in A}p=s\right\}.$$
Die Randbedingung lautet
$$C(m,0)=1,\qquad C(m,s)=0\quad(s\gt0).$$
Für \(i\lt m\) wird \(p_i\) entweder ausgelassen oder benutzt. Daher gilt
$$C(i,s)=C(i+1,s)+ \begin{cases} C(i+1,s-p_i), & s\ge p_i,\\ 0, & s\lt p_i. \end{cases}$$
Das ist die bekannte Teilmengen-Summen-Rekurrenz, aber die Tabelle dient hier als Rang-Orakel. Die Gesamtzahl der Primzahllisten ist \(M=C(0,N)\). Weil diese Werte groß werden können, verwenden die Implementierungen beliebig große Ganzzahlen.
In lexikographischer Ordnung kommen alle Listen mit erstem Element \(p_a\) vor allen Listen mit erstem Element \(p_b\), wenn \(p_a\lt p_b\). Probiert man als erstes Element \(p_i\), dann ist die Anzahl der damit beginnenden Listen genau
$$C(i+1,N-p_i),$$
denn alle weiteren Einträge müssen größere Primzahlen sein und die Restsumme \(N-p_i\) bilden. Jeder Kandidat für das erste Element bildet daher einen zusammenhängenden lexikographischen Block.
Nach einem bereits festgelegten Präfix gilt dasselbe. Ist die aktuelle Restsumme bekannt, dann trägt ein Kandidat \(p_j\) einen Block der Größe
$$C(j+1,R-p_j)$$
bei. Diese Größe entscheidet, ob der gesuchte Rang in diesem Block liegt oder erst danach kommt.
Setze \(r=\lfloor(M+1)/2\rfloor\). Beginne mit Restsumme \(N\) und dem ersten erlaubten Primindex \(0\). Die Kandidaten werden aufsteigend geprüft. Für einen Kandidaten \(p_i\) berechnet man
$$B_i=C(i+1,R-p_i).$$
Ist \(r>B_i\), liegt der ganze Block vor dem Median und wird übersprungen:
$$r\leftarrow r-B_i.$$
Ist \(r\le B_i\), enthält dieser Block den Median. Dann wird \(p_i\) an die Antwort angehängt, die Restsumme um \(p_i\) verringert, und die Suche geht nur mit größeren Primzahlen weiter. Bei Restsumme \(0\) ist die Liste vollständig rekonstruiert.
Die DP liefert \(C(0,20)=4\), also \(r=\lfloor(4+1)/2\rfloor=2\). Der erste Kandidat \(2\) besitzt
$$C(1,18)=2,$$
nämlich die Listen \((2,5,13)\) und \((2,7,11)\). Da \(r=2\) in diesem Block liegt, ist das erste Element \(2\).
Die Restsumme ist nun \(18\). Der Kandidat \(3\) hat keine gültige Vervollständigung, \(5\) hat genau eine Vervollständigung \((13)\), und \(7\) hat genau eine Vervollständigung \((11)\). Nach dem Überspringen des Blocks für \(5\) wird der Rang \(1\), also wird \(7\) gewählt. Danach erzwingt die Restsumme \(11\) die letzte Primzahl \(11\). Die Median-Liste ist \((2,7,11)\).
primes_up_to erzeugt die Primzahlen mit einem Sieb. build_dp füllt die Suffix-Tabelle \(C(i,s)\) rückwärts vom letzten Primindex aus. Für die Zählwerte werden beliebig große Ganzzahlen genutzt.
kth_prime_list führt das lexikographische Ent-Ranken durch. Zu jedem Kandidaten fragt es die DP-Tabelle nach der Anzahl gültiger Vervollständigungen. Ganze Blöcke werden durch Subtraktion übersprungen; der erste Block, der den Rang enthält, bestimmt die nächste Primzahl der Antwort.
median_prime_list wandelt die Gesamtzahl in den Medianrang \((M+1)//2\) um. Danach multipliziert product_mod die ausgewählten Primzahlen modulo \(10^9\), da nur die letzten neun Ziffern gefragt sind.
Die Kontrollpunkte prüfen das Beispiel \(N=20\) und vergleichen für alle Zielwerte von \(2\) bis \(60\) DP-Zählung, ersten Rang, Medianrang und letzten Rang mit einer direkten Brute-Force-Aufzählung.
Sei \(m=\pi(N)\) die Anzahl der Primzahlen höchstens \(N\). Die DP-Tabelle hat \((m+1)(N+1)\) Einträge und wird in \(O(mN)\) arithmetischen Schritten gefüllt. Das Ent-Ranken ist durch \(O(mL)\) beschränkt, wobei \(L\) die Länge der Median-Liste ist.
Der Speicherbedarf beträgt \(O(mN)\) große Ganzzahlen. Für \(N=2026\) ist \(m=306\), sodass die Tabelle praktisch klein bleibt.
Toplamı hedef değer \(N\) olan, sıkı biçimde artan asal listelerinin tamamını düşünelim. Bu listeler lexicographic sıraya konur ve istenen liste bu sıralamanın medyanıdır. Liste sayısı çiftse önce son liste atılır. Dolayısıyla toplam liste sayısı \(M\) ise aranan bir-bazlı sıra
$$r=\left\lfloor\frac{M+1}{2}\right\rfloor$$
olur. \(N=20\) için listeler \((2,5,13)\), \((2,7,11)\), \((3,17)\) ve \((7,13)\)'tür. \(M=4\) olduğundan etkili medyan sırası \(2\)'dir ve sonuç \((2,7,11)\) olur. Asıl soru \(N=2026\) için bu medyan listedeki asal sayıların çarpımının son dokuz basamağını ister.
Her liste sıkı biçimde arttığı için, geçerli her liste \(N\)'den büyük olmayan asalların bir altkümesidir; yalnızca artan sırada yazılmıştır ve elemanlarının toplamı \(N\)'dir. Eğer
$$p_0 \lt p_1 \lt \cdots \lt p_{m-1}$$
\(N\)'e kadar olan asallarsa, amaç tüm altkümeleri üretmek değil, lexicographic sırada medyana doğrudan gidecek kadar sayım yapmaktır.
Sıkı artış koşulu burada yapıyı belirler: \(p_i\) seçildikten sonra listedeki sonraki asallar ancak \(p_{i+1},p_{i+2},\dots\) içinden gelebilir. Bu da doğal bir suffix dinamik programlama tablosu verir.
Şunu tanımlayalım:
$$C(i,s)=\#\left\{A\subseteq\{p_i,p_{i+1},\dots,p_{m-1}\}:\sum_{p\in A}p=s\right\}.$$
Sınır koşulu
$$C(m,0)=1,\qquad C(m,s)=0\quad(s\gt0)$$
şeklindedir. \(i\lt m\) için \(p_i\) ya kullanılmaz ya da kullanılır:
$$C(i,s)=C(i+1,s)+ \begin{cases} C(i+1,s-p_i), & s\ge p_i,\\ 0, & s\lt p_i. \end{cases}$$
Bu altküme-toplamı dinamik programlamasıdır; ancak burada tablo sadece var/yok cevabı için değil, sıralamada blok boyutlarını ölçmek için kullanılır. Toplam liste sayısı \(M=C(0,N)\)'dir. Bu değerler sabit genişlikli tamsayıları aşabileceğinden kodlar büyük tamsayı kullanır.
Lexicographic sırada ilk elemanı \(p_a\) olan tüm listeler, ilk elemanı \(p_b\) olan listelerden önce gelir; yeter ki \(p_a\lt p_b\) olsun. İlk eleman olarak \(p_i\) denenirse, bu elemanla başlayan liste sayısı tam olarak
$$C(i+1,N-p_i)$$
olur; çünkü geriye kalan elemanlar daha büyük asallardan seçilmeli ve \(N-p_i\) toplamını vermelidir. Bu yüzden her ilk asal adayı lexicographic sıralamada bitişik bir blok oluşturur.
Aynı argüman sabitlenmiş bir önekten sonra da geçerlidir. Mevcut kalan toplam biliniyorsa, sıradaki aday \(p_j\) için blok boyutu
$$C(j+1,R-p_j)$$
olur. Bu sayı, istenen sıranın o blokta mı yoksa sonrasında mı olduğunu söyler.
\(r=\lfloor(M+1)/2\rfloor\) alınır. Başlangıçta kalan toplam \(N\), ilk izinli asal indeksi \(0\)'dır. Aday asallar artan sırada gezilir. \(p_i\) adayı için
$$B_i=C(i+1,R-p_i)$$
hesaplanır. Eğer \(r>B_i\) ise bu blok medyandan tamamen önce gelir ve atlanır:
$$r\leftarrow r-B_i.$$
Eğer \(r\le B_i\) ise medyan liste bu bloktadır. \(p_i\) cevaba eklenir, kalan toplam \(p_i\) kadar azaltılır ve yalnızca daha büyük asallarla devam edilir. Kalan toplam \(0\) olduğunda liste tamamlanmıştır.
DP tablosu \(C(0,20)=4\) verir; bu yüzden \(r=\lfloor(4+1)/2\rfloor=2\). İlk aday \(2\) için
$$C(1,18)=2$$
olur; bunlar \((2,5,13)\) ve \((2,7,11)\) listeleridir. \(r=2\) bu bloğun içinde olduğundan ilk eleman \(2\)'dir.
Artık kalan toplam \(18\)'dir. \(3\) adayı geçerli tamamlamaya sahip değildir; \(5\) adayı \((13)\) ile bir tamamlamaya sahiptir; \(7\) adayı da \((11)\) ile bir tamamlamaya sahiptir. \(5\)'in bloğu atlanınca sıra \(1\)'e düşer ve \(7\) seçilir. Son kalan \(11\) olduğu için son asal \(11\)'dir. Medyan liste \((2,7,11)\) olur.
primes_up_to asal listesini elek ile çıkarır. build_dp, \(C(i,s)\) suffix tablosunu sondan başa doldurur. Sayımlar büyük olabileceği için C++ cpp_int, Python doğal büyük tamsayıları, Java ise BigInteger kullanır.
kth_prime_list lexicographic unranking yapar. Her aday asal için DP tablosundan geçerli tamamlanma sayısını okur. Blok tamamen önce geliyorsa sıra azaltılır; sırayı içeren ilk blok bir sonraki asalın hangisi olduğunu belirler.
median_prime_list, toplam liste sayısını \((M+1)//2\) medyan sırasına çevirir. product_mod ise seçilen asalları \(10^9\) modunda çarpar; çünkü yalnızca son dokuz basamak gerekir.
Kontrol noktaları \(N=20\) örneğini ve \(2\) ile \(60\) arasındaki tüm hedefleri brute-force ile doğrular: DP sayısı, ilk sıra, medyan sıra ve son sıra doğrudan üretilen listelerle karşılaştırılır.
\(m=\pi(N)\), yani \(N\)'den büyük olmayan asal sayısı olsun. DP tablosu \((m+1)(N+1)\) hücre içerir ve \(O(mN)\) aritmetik işlemle doldurulur. Unranking kısmı en fazla \(O(mL)\) aday kontrol eder; burada \(L\) medyan listenin uzunluğudur.
Bellek kullanımı \(O(mN)\) büyük tamsayıdır. \(N=2026\) için \(m=306\) olduğundan tablo pratikte küçüktür.
Consideramos todas las listas de primos estrictamente crecientes cuya suma es un objetivo \(N\). Las listas se ordenan lexicográficamente y se pide la lista mediana. Si el número de listas es par, primero se descarta la última; por tanto, si hay \(M\) listas, el rango buscado, contando desde \(1\), es
$$r=\left\lfloor\frac{M+1}{2}\right\rfloor.$$
Para \(N=20\), las cuatro listas son \((2,5,13)\), \((2,7,11)\), \((3,17)\) y \((7,13)\). Como \(M=4\), el rango mediano efectivo es \(2\), que da \((2,7,11)\). La instancia real usa \(N=2026\) y solo pide los últimos nueve dígitos del producto de los primos de la lista mediana.
Como cada lista es estrictamente creciente, cada lista válida es exactamente un subconjunto de los primos no mayores que \(N\), escrito en orden creciente, cuyos elementos suman \(N\). Si
$$p_0 \lt p_1 \lt \cdots \lt p_{m-1}$$
son los primos hasta \(N\), no conviene enumerar todos los subconjuntos. Conviene contar bloques para saltar directamente a la mediana dentro del orden lexicográfico.
La condición de crecimiento estricto es la clave: después de elegir \(p_i\), todos los primos posteriores deben venir de \(p_{i+1},p_{i+2},\dots\). Esto produce una programación dinámica por sufijos.
Definimos
$$C(i,s)=\#\left\{A\subseteq\{p_i,p_{i+1},\dots,p_{m-1}\}:\sum_{p\in A}p=s\right\}.$$
La condición inicial es
$$C(m,0)=1,\qquad C(m,s)=0\quad(s\gt0).$$
Para \(i\lt m\), el primo \(p_i\) se omite o se usa:
$$C(i,s)=C(i+1,s)+ \begin{cases} C(i+1,s-p_i), & s\ge p_i,\\ 0, & s\lt p_i. \end{cases}$$
Es la recurrencia de suma de subconjuntos, pero aquí la tabla funciona como un oráculo de rangos. El número total de listas es \(M=C(0,N)\). Las cuentas pueden ser grandes, así que las implementaciones usan enteros de precisión arbitraria.
En orden lexicográfico, todas las listas que empiezan por \(p_a\) aparecen antes que las que empiezan por \(p_b\) si \(p_a\lt p_b\). Si probamos \(p_i\) como primer primo, el número de listas que empiezan con él es
$$C(i+1,N-p_i),$$
porque el resto debe usar primos mayores y sumar \(N-p_i\). Cada candidato para el primer elemento forma un bloque contiguo.
Tras fijar un prefijo ocurre lo mismo. Si la suma restante es conocida, el candidato \(p_j\) aporta un bloque de tamaño
$$C(j+1,R-p_j).$$
Ese tamaño indica si el rango buscado cae dentro de ese bloque o después de él.
Tomamos \(r=\lfloor(M+1)/2\rfloor\). Empezamos con suma restante \(N\) y con índice mínimo permitido \(0\). Para cada candidato \(p_i\) se calcula
$$B_i=C(i+1,R-p_i).$$
Si \(r>B_i\), todo ese bloque está antes de la mediana y se descuenta:
$$r\leftarrow r-B_i.$$
Si \(r\le B_i\), la mediana está dentro de ese bloque. Se añade \(p_i\), se reduce la suma restante y se continúa solo con primos mayores. Cuando la suma restante llega a \(0\), la lista ya está reconstruida.
La DP da \(C(0,20)=4\), por lo que \(r=\lfloor(4+1)/2\rfloor=2\). El primer candidato \(2\) tiene
$$C(1,18)=2,$$
que corresponde a \((2,5,13)\) y \((2,7,11)\). Como \(r=2\) está dentro del bloque, el primer elemento es \(2\).
La suma restante es \(18\). El candidato \(3\) no tiene completación válida, \(5\) tiene una completación \((13)\), y \(7\) tiene una completación \((11)\). Al saltar el bloque de \(5\), el rango pasa a \(1\), así que se elige \(7\). La suma restante \(11\) fuerza el último primo \(11\). La lista mediana es \((2,7,11)\).
primes_up_to construye la lista de primos con una criba. build_dp rellena la tabla de sufijos \(C(i,s)\) desde el final hacia el principio, con enteros grandes para las cuentas.
kth_prime_list hace el des-ranqueo lexicográfico. Para cada candidato pregunta a la tabla cuántas completaciones válidas existen. Los bloques completos se saltan restando sus tamaños, y el primer bloque que contiene el rango determina el siguiente primo.
median_prime_list convierte el total en el rango mediano \((M+1)//2\). Finalmente product_mod multiplica los primos seleccionados módulo \(10^9\), suficiente para obtener los últimos nueve dígitos.
Los puntos de control verifican el ejemplo \(N=20\) y comparan, para todos los objetivos de \(2\) a \(60\), las cuentas y los rangos contra una enumeración directa.
Sea \(m=\pi(N)\). La tabla tiene \((m+1)(N+1)\) entradas y se llena en \(O(mN)\) operaciones aritméticas. El des-ranqueo queda acotado por \(O(mL)\), donde \(L\) es la longitud de la lista mediana.
La memoria es \(O(mN)\) enteros de precisión arbitraria. Para \(N=2026\), \(m=306\), así que la tabla es pequeña en la práctica.
我们考虑所有由严格递增素数组成、和为目标值 \(N\) 的列表。把这些列表按字典序排列后,题目要求其中的中位列表。如果列表总数为偶数,先丢弃最后一个列表;等价地,若总数为 \(M\),需要的一基排名是
$$r=\left\lfloor\frac{M+1}{2}\right\rfloor.$$
当 \(N=20\) 时,四个列表是 \((2,5,13)\)、\((2,7,11)\)、\((3,17)\)、\((7,13)\)。因为 \(M=4\),有效中位排名为 \(2\),得到 \((2,7,11)\)。实际问题使用 \(N=2026\),只要求中位列表中素数乘积的最后九位。
由于列表必须严格递增,每个合法列表正好是“不超过 \(N\) 的素数”的一个子集,只是按递增顺序写出,并且元素和为 \(N\)。设
$$p_0 \lt p_1 \lt \cdots \lt p_{m-1}$$
是不超过 \(N\) 的全部素数。我们不需要枚举所有子集,而是要计算足够的块大小,从而直接跳到字典序中的中位位置。
严格递增条件非常关键:一旦选择了 \(p_i\),后面的元素只能来自 \(p_{i+1},p_{i+2},\dots\)。这自然给出一个后缀动态规划。
定义
$$C(i,s)=\#\left\{A\subseteq\{p_i,p_{i+1},\dots,p_{m-1}\}:\sum_{p\in A}p=s\right\}.$$
边界条件是
$$C(m,0)=1,\qquad C(m,s)=0\quad(s\gt0).$$
当 \(i\lt m\) 时,\(p_i\) 要么不选,要么选:
$$C(i,s)=C(i+1,s)+ \begin{cases} C(i+1,s-p_i), & s\ge p_i,\\ 0, & s\lt p_i. \end{cases}$$
这就是子集和递推,但这里的表不仅回答可行性,还作为排名查询表。总列表数是 \(M=C(0,N)\)。这些计数可能很大,因此实现中使用任意精度整数。
在字典序中,如果 \(p_a\lt p_b\),那么所有以 \(p_a\) 开头的列表都排在所有以 \(p_b\) 开头的列表之前。若尝试把 \(p_i\) 作为第一个素数,则以它开头的列表数正好是
$$C(i+1,N-p_i),$$
因为剩下的元素必须从更大的素数中选择,并且和为 \(N-p_i\)。所以每个首元素候选对应一个连续的字典序块。
固定一个前缀后同理。若当前剩余和已知,候选 \(p_j\) 对应的块大小为
$$C(j+1,R-p_j).$$
这个块大小告诉我们目标排名是在块内,还是在块之后。
令 \(r=\lfloor(M+1)/2\rfloor\)。初始剩余和为 \(N\),最小允许素数下标为 \(0\)。按递增顺序扫描候选素数。对候选 \(p_i\),计算
$$B_i=C(i+1,R-p_i).$$
若 \(r>B_i\),整个块都在中位列表之前,直接跳过:
$$r\leftarrow r-B_i.$$
若 \(r\le B_i\),中位列表就在这个块中。把 \(p_i\) 加入答案,从剩余和中减去 \(p_i\),然后只允许更大的素数继续。剩余和变为 \(0\) 时,列表已经完整重建。
DP 给出 \(C(0,20)=4\),所以 \(r=\lfloor(4+1)/2\rfloor=2\)。第一个候选 \(2\) 有
$$C(1,18)=2,$$
对应 \((2,5,13)\) 与 \((2,7,11)\)。因为 \(r=2\) 落在此块内,第一个元素是 \(2\)。
现在剩余和为 \(18\)。候选 \(3\) 没有合法补全;候选 \(5\) 有一个补全 \((13)\);候选 \(7\) 有一个补全 \((11)\)。跳过 \(5\) 的块后,排名变为 \(1\),于是选择 \(7\)。最后剩余 \(11\),强制选择素数 \(11\)。中位列表为 \((2,7,11)\)。
primes_up_to 用筛法生成素数表。build_dp 从最后一个素数向前填充后缀表 \(C(i,s)\),计数使用大整数。
kth_prime_list 执行字典序反排名。它对每个候选素数查询 DP 表中的合法补全数;若整个块在目标之前,就减去块大小;第一个包含目标排名的块决定答案中的下一个素数。
median_prime_list 把总数转换为中位排名 \((M+1)//2\)。最后 product_mod 把选出的素数在 \(10^9\) 模下相乘,因为只需要最后九位。
校验部分检查 \(N=20\) 的例子,并对 \(2\) 到 \(60\) 的每个目标与直接枚举比较,验证 DP 计数、第一排名、中位排名和最后排名。
设 \(m=\pi(N)\)。DP 表有 \((m+1)(N+1)\) 个条目,填表需要 \(O(mN)\) 次算术操作。反排名过程至多为 \(O(mL)\),其中 \(L\) 是中位列表长度。
内存为 \(O(mN)\) 个任意精度整数。对于 \(N=2026\),\(m=306\),实际规模很小。
Рассматриваются все списки строго возрастающих простых чисел, сумма которых равна целевому значению \(N\). Эти списки упорядочиваются лексикографически, и требуется медианный список. Если число списков чётно, сначала отбрасывается последний список; значит, при общем числе списков \(M\) нужный одноиндексный ранг равен
$$r=\left\lfloor\frac{M+1}{2}\right\rfloor.$$
Для \(N=20\) существуют четыре списка: \((2,5,13)\), \((2,7,11)\), \((3,17)\), \((7,13)\). Так как \(M=4\), эффективный медианный ранг равен \(2\), и получается \((2,7,11)\). В основной задаче \(N=2026\), а требуется только последние девять цифр произведения простых чисел из медианного списка.
Поскольку каждый список строго возрастает, любой допустимый список является подмножеством простых чисел, не превосходящих \(N\), записанным в возрастающем порядке, с суммой элементов \(N\). Пусть
$$p_0 \lt p_1 \lt \cdots \lt p_{m-1}$$
это все простые числа до \(N\). Перебирать все подмножества не нужно; нужно уметь считать блоки, чтобы перейти прямо к медиане в лексикографическом порядке.
Строгое возрастание задаёт структуру: после выбора \(p_i\) все последующие элементы могут быть только среди \(p_{i+1},p_{i+2},\dots\). Отсюда возникает динамика по суффиксам.
Определим
$$C(i,s)=\#\left\{A\subseteq\{p_i,p_{i+1},\dots,p_{m-1}\}:\sum_{p\in A}p=s\right\}.$$
Граничные условия:
$$C(m,0)=1,\qquad C(m,s)=0\quad(s\gt0).$$
Для \(i\lt m\) простое \(p_i\) либо не берётся, либо берётся:
$$C(i,s)=C(i+1,s)+ \begin{cases} C(i+1,s-p_i), & s\ge p_i,\\ 0, & s\lt p_i. \end{cases}$$
Это рекуррентная формула subset sum, но таблица здесь используется как оракул ранжирования. Общее число списков равно \(M=C(0,N)\). Значения могут быть большими, поэтому реализации используют целые числа произвольной точности.
В лексикографическом порядке все списки, начинающиеся с \(p_a\), идут раньше всех списков, начинающихся с \(p_b\), если \(p_a\lt p_b\). Если первым элементом попробовать \(p_i\), то число списков с таким началом равно
$$C(i+1,N-p_i),$$
поскольку остальные элементы должны быть большими простыми и иметь сумму \(N-p_i\). Значит, каждый кандидат первого элемента образует один непрерывный блок.
После фиксированного префикса рассуждение такое же. При известной оставшейся сумме кандидат \(p_j\) даёт блок размера
$$C(j+1,R-p_j).$$
Этот размер показывает, находится ли нужный ранг внутри блока или после него.
Берём \(r=\lfloor(M+1)/2\rfloor\). Начинаем с остатка \(N\) и минимального допустимого индекса \(0\). Кандидаты просматриваются по возрастанию. Для \(p_i\) вычисляется
$$B_i=C(i+1,R-p_i).$$
Если \(r>B_i\), весь блок находится до медианы, и его можно пропустить:
$$r\leftarrow r-B_i.$$
Если \(r\le B_i\), медианный список находится в этом блоке. Тогда \(p_i\) добавляется к ответу, остаток уменьшается на \(p_i\), и дальше разрешены только большие простые. Когда остаток становится \(0\), список полностью восстановлен.
Динамика даёт \(C(0,20)=4\), поэтому \(r=\lfloor(4+1)/2\rfloor=2\). Первый кандидат \(2\) имеет
$$C(1,18)=2,$$
что соответствует спискам \((2,5,13)\) и \((2,7,11)\). Так как \(r=2\) находится внутри этого блока, первый элемент равен \(2\).
Теперь остаток равен \(18\). Кандидат \(3\) не имеет допустимого дополнения, кандидат \(5\) имеет одно дополнение \((13)\), а кандидат \(7\) имеет одно дополнение \((11)\). После пропуска блока для \(5\) ранг становится \(1\), поэтому выбирается \(7\). Оставшаяся сумма \(11\) вынуждает последний простой \(11\). Медианный список: \((2,7,11)\).
primes_up_to строит список простых с помощью решета. build_dp заполняет суффиксную таблицу \(C(i,s)\) от конца к началу, используя большие целые для счётчиков.
kth_prime_list выполняет лексикографическое восстановление по рангу. Для каждого кандидата оно спрашивает у DP-таблицы число допустимых дополнений. Целые блоки пропускаются вычитанием их размеров, а первый блок, содержащий ранг, определяет следующий простой.
median_prime_list превращает общее число списков в медианный ранг \((M+1)//2\). Затем product_mod умножает выбранные простые по модулю \(10^9\), поскольку нужны только последние девять цифр.
Контрольные проверки включают пример \(N=20\) и прямой перебор всех целей от \(2\) до \(60\), сравнивая число списков, первый ранг, медианный ранг и последний ранг.
Пусть \(m=\pi(N)\). Таблица имеет \((m+1)(N+1)\) ячеек и заполняется за \(O(mN)\) арифметических операций. Восстановление по рангу ограничено \(O(mL)\), где \(L\) — длина медианного списка.
Память составляет \(O(mN)\) больших целых чисел. Для \(N=2026\) имеем \(m=306\), так что таблица практически невелика.
ننظر إلى كل القوائم المكوّنة من أعداد أولية متزايدة بصرامة، بحيث يكون مجموعها هو الهدف \(N\). ترتّب هذه القوائم ترتيباً معجمياً، والمطلوب هو القائمة الوسطى. إذا كان عدد القوائم زوجياً، تُهمل القائمة الأخيرة أولاً؛ وبذلك، إذا كان عدد القوائم \(M\)، فإن الرتبة المطلوبة، مع العد من \(1\)، هي
$$r=\left\lfloor\frac{M+1}{2}\right\rfloor.$$
عند \(N=20\) تكون القوائم الأربع هي \((2,5,13)\)، \((2,7,11)\)، \((3,17)\)، \((7,13)\). وبما أن \(M=4\)، فالرتبة الوسطى الفعلية هي \(2\)، أي \((2,7,11)\). في المسألة الأصلية نستخدم \(N=2026\)، والمطلوب فقط آخر تسعة أرقام من حاصل ضرب الأعداد الأولية في القائمة الوسطى.
لأن كل قائمة متزايدة بصرامة، فإن كل قائمة صالحة هي بالضبط مجموعة جزئية من الأعداد الأولية التي لا تتجاوز \(N\)، مكتوبة بترتيب تصاعدي، ومجموع عناصرها يساوي \(N\). إذا كانت
$$p_0 \lt p_1 \lt \cdots \lt p_{m-1}$$
هي الأعداد الأولية حتى \(N\)، فليس الهدف توليد كل المجموعات الجزئية، بل حساب أحجام كتل كافية للوصول مباشرة إلى الوسط في الترتيب المعجمي.
شرط التزايد الصارم هو ما يجعل المسألة منظمة: بعد اختيار \(p_i\)، لا يمكن للعناصر اللاحقة إلا أن تأتي من \(p_{i+1},p_{i+2},\dots\). لذلك نحصل على برمجة ديناميكية على اللواحق.
نعرّف
$$C(i,s)=\#\left\{A\subseteq\{p_i,p_{i+1},\dots,p_{m-1}\}:\sum_{p\in A}p=s\right\}.$$
شرط البداية هو
$$C(m,0)=1,\qquad C(m,s)=0\quad(s\gt0).$$
عندما \(i\lt m\)، فإما أن نتجاوز \(p_i\) أو نستخدمه:
$$C(i,s)=C(i+1,s)+ \begin{cases} C(i+1,s-p_i), & s\ge p_i,\\ 0, & s\lt p_i. \end{cases}$$
هذه هي علاقة مسألة مجموع المجموعات الجزئية، لكن الجدول هنا يعمل كدليل للرتب. العدد الكلي للقوائم هو \(M=C(0,N)\). وقد تكون هذه القيم كبيرة، لذلك تستخدم النسخ البرمجية أعداداً صحيحة بدقة غير محدودة.
في الترتيب المعجمي، كل القوائم التي تبدأ بـ \(p_a\) تأتي قبل كل القوائم التي تبدأ بـ \(p_b\) متى كان \(p_a\lt p_b\). إذا جرّبنا \(p_i\) كأول عنصر، فإن عدد القوائم التي تبدأ به هو تماماً
$$C(i+1,N-p_i),$$
لأن باقي العناصر يجب أن تكون أعداداً أولية أكبر، ويجب أن يكون مجموعها \(N-p_i\). وهكذا يعطي كل مرشح لأول عنصر كتلة متصلة في الترتيب المعجمي.
بعد تثبيت بادئة ما، ينطبق المنطق نفسه. إذا عرفنا المجموع المتبقي، فإن المرشح \(p_j\) يعطي كتلة حجمها
$$C(j+1,R-p_j).$$
هذا الحجم يخبرنا هل الرتبة المطلوبة داخل تلك الكتلة أم بعدها.
نأخذ \(r=\lfloor(M+1)/2\rfloor\). نبدأ بالمجموع المتبقي \(N\)، وبأول فهرس مسموح \(0\). نفحص الأعداد الأولية المرشحة تصاعدياً. للمرشح \(p_i\) نحسب
$$B_i=C(i+1,R-p_i).$$
إذا كان \(r>B_i\)، فالكتلة كلها تأتي قبل القائمة الوسطى، ولذلك نتجاوزها:
$$r\leftarrow r-B_i.$$
إذا كان \(r\le B_i\)، فالقائمة الوسطى داخل هذه الكتلة. نضيف \(p_i\) إلى الجواب، وننقص المجموع المتبقي بمقدار \(p_i\)، ثم نتابع فقط مع أعداد أولية أكبر. عندما يصبح المتبقي \(0\)، تكون القائمة قد أعيد بناؤها كاملة.
يعطي جدول DP القيمة \(C(0,20)=4\)، ومن ثم \(r=\lfloor(4+1)/2\rfloor=2\). المرشح الأول \(2\) يملك
$$C(1,18)=2,$$
وهما القائمتان \((2,5,13)\) و \((2,7,11)\). بما أن \(r=2\) داخل هذه الكتلة، فإن العنصر الأول هو \(2\).
الآن المتبقي \(18\). المرشح \(3\) لا يملك إكمالاً صالحاً، والمرشح \(5\) يملك إكمالاً واحداً \((13)\)، والمرشح \(7\) يملك إكمالاً واحداً \((11)\). بعد تجاوز كتلة \(5\)، تصبح الرتبة \(1\)، فنختار \(7\). بعد ذلك يفرض المتبقي \(11\) اختيار العدد الأولي \(11\). إذن القائمة الوسطى هي \((2,7,11)\).
الدالة primes_up_to تبني قائمة الأعداد الأولية باستخدام الغربال. والدالة build_dp تملأ جدول اللواحق \(C(i,s)\) من النهاية إلى البداية، مع استخدام أعداد صحيحة كبيرة للعدّ.
الدالة kth_prime_list تنفذ استخراج القائمة من رتبتها في الترتيب المعجمي. لكل مرشح، تسأل جدول DP عن عدد الإكمالات الصالحة. إذا كانت الكتلة كلها قبل الرتبة المطلوبة، يُطرح حجمها؛ وأول كتلة تحتوي الرتبة تحدد العدد الأولي التالي.
الدالة median_prime_list تحول العدد الكلي إلى الرتبة الوسطى \((M+1)//2\). وفي النهاية تضرب product_mod الأعداد الأولية المختارة بترديد \(10^9\)، لأن المطلوب هو آخر تسعة أرقام فقط.
تتحقق نقاط الاختبار من مثال \(N=20\)، ثم تقارن كل الأهداف من \(2\) إلى \(60\) مع تعداد مباشر، للتأكد من عدد القوائم والرتبة الأولى والرتبة الوسطى والرتبة الأخيرة.
ليكن \(m=\pi(N)\)، أي عدد الأعداد الأولية التي لا تتجاوز \(N\). يحتوي جدول DP على \((m+1)(N+1)\) خانة، ويُملأ في \(O(mN)\) عملية حسابية. أما استخراج القائمة من الرتبة فحده \(O(mL)\)، حيث \(L\) طول القائمة الوسطى.
استخدام الذاكرة هو \(O(mN)\) من الأعداد الصحيحة الكبيرة. عند \(N=2026\)، لدينا \(m=306\)، ولذلك يبقى الجدول صغيراً عملياً.