In Nim Square, a move on one heap of size \(n\) removes any positive square \(k^2\le n\). The position has three heaps, and we must count how many ordered-by-size triples
$$0\le a\le b\le c\le N$$
are losing positions.
For one heap, the legal moves are
$$n\to n-1,\ n-4,\ n-9,\dots$$
for every square not exceeding \(n\). So the Grundy value of a single heap is
$$g(0)=0,$$
$$g(n)=\operatorname{mex}\{g(n-k^2):k^2\le n\}.$$
This is the usual subtract-a-square recurrence.
The full game is the disjoint sum of three impartial subgames. Therefore Sprague-Grundy theory says that the triple \((a,b,c)\) is losing exactly when the nim-sum vanishes:
$$g(a)\oplus g(b)\oplus g(c)=0.$$
So once the array \(g(0),\dots,g(N)\) is known, the entire counting problem becomes a combinatorial xor-counting problem.
The first few single-heap values are
$$g(0..4)=(0,1,0,1,2).$$
For instance:
$$g(1)=\operatorname{mex}\{g(0)\}=\operatorname{mex}\{0\}=1,$$
$$g(2)=\operatorname{mex}\{g(1)\}=\operatorname{mex}\{1\}=0,$$
$$g(4)=\operatorname{mex}\{g(3),g(0)\}=\operatorname{mex}\{1,0\}=2.$$
If \(N=4\), the losing triples are
$$\begin{aligned} &(0,0,0),(0,0,2),(0,1,1),(0,1,3),(0,2,2),(0,3,3),\\ &(0,4,4),(1,1,2),(1,2,3),(2,2,2),(2,3,3),(2,4,4), \end{aligned}$$
so the count is \(12\).
A direct scan over all triples \((a,b,c)\) would take
$$O(N^3)$$
time, which is impossible for \(N=100000\). The code instead reorganizes the count by fixing the middle heap \(b\).
Fix \(b\). Then:
Left side: \(a\) may range over \(0\le a\le b\).
Right side: \(c\) may range over \(b\le c\le N\).
Let
$$\text{pref}[x]=\#\{a\le b:g(a)=x\},$$
$$\text{suf}[y]=\#\{c\ge b:g(c)=y\}.$$
For a fixed Grundy value \(x=g(a)\), the losing condition
$$x\oplus g(b)\oplus g(c)=0$$
forces
$$g(c)=x\oplus g(b).$$
Hence the number of losing triples with this middle value \(b\) is
$$\text{add}_b=\sum_x \text{pref}[x]\cdot \text{suf}[x\oplus g(b)].$$
Summing \(\text{add}_b\) over all \(b\) gives the final answer.
The implementation maintains the arrays in a very specific order:
Before counting for \(b\): it adds \(g(b)\) to the prefix array.
During counting: prefix therefore represents \(a\in[0,b]\), while suffix still represents \(c\in[b,N]\).
After counting: it removes \(g(b)\) from suffix, so the next step uses \(c\ge b+1\).
This means the ordering constraint is built directly into the data structure update order; no extra combinatorial correction is needed.
1) Build Grundy table. build_grundy(limit) computes the subtract-a-square Grundy values using a timestamp-based mex array.
2) Determine Grundy alphabet size. The code records
$$\max g(n)$$
so it knows how large the prefix and suffix frequency arrays must be.
3) Initialize suffix. Initially all heaps \(0,\dots,N\) are available on the right, so suffix counts every Grundy value in the full range.
4) Sweep the middle index. For each \(b\), the code updates prefix, applies the xor-count formula above, then removes \(b\) from suffix.
5) Checkpoints. The C++ version verifies
$$\texttt{solve(29)}=1160$$
and also checks that \(\texttt{solve(40)}\) matches a literal brute-force triple scan.
6) Final Project Euler value. For the required bound \(N=100000\), the implementation returns
$$2586528661783.$$
Computing the Grundy table costs about \(O(N\sqrt N)\), because each \(g(n)\) examines all squares up to \(n\). The counting sweep costs \(O(N\cdot G)\), where \(G\) is the number of distinct Grundy values encountered, which stays small in practice. Memory usage is \(O(N+G)\).
Bei Nim Square darf man aus einem Haufen der Größe \(n\) jede positive Quadratzahl \(k^2\le n\) entfernen. Gesucht ist die Anzahl verlorener Tripel
$$0\le a\le b\le c\le N.$$
Für einen Haufen sind die Züge
$$n\to n-1,\ n-4,\ n-9,\dots$$
für alle Quadrate \(\le n\). Daher gilt
$$g(0)=0,$$
$$g(n)=\operatorname{mex}\{g(n-k^2):k^2\le n\}.$$
Das Gesamtsystem ist die disjunkte Summe dreier impartial games. Also ist \((a,b,c)\) genau dann verloren, wenn
$$g(a)\oplus g(b)\oplus g(c)=0.$$
Die ersten Werte lauten
$$g(0..4)=(0,1,0,1,2).$$
Für \(N=4\) ergeben sich genau 12 verlorene Tripel, etwa \((0,0,0)\), \((0,1,1)\), \((1,2,3)\), \((2,2,2)\) usw. Dieses kleine Beispiel zeigt, dass die Aufgabe nicht in der Spieltheorie selbst, sondern im effizienten Zählen aller xor-Null-Tripel liegt.
Ein direkter Dreifach-Loop über alle \((a,b,c)\) hätte Aufwand
$$O(N^3),$$
also völlig unpraktisch für \(N=100000\).
Fixiere den mittleren Haufen \(b\). Dann gilt
$$0\le a\le b,\qquad b\le c\le N.$$
Definiere Häufigkeiten
$$\text{pref}[x]=\#\{a\le b:g(a)=x\},$$
$$\text{suf}[y]=\#\{c\ge b:g(c)=y\}.$$
Aus
$$g(a)\oplus g(b)\oplus g(c)=0$$
folgt für \(x=g(a)\):
$$g(c)=x\oplus g(b).$$
Also ist der Beitrag des festen Mittels \(b\)
$$\text{add}_b=\sum_x \text{pref}[x]\cdot \text{suf}[x\oplus g(b)].$$
Vor dem Zählen für \(b\) wird \(g(b)\) bereits in das Präfix aufgenommen. Während des Zählens enthält das Präfix also genau die Werte für \(a\in[0,b]\), das Suffix aber noch die Werte für \(c\in[b,N]\). Erst danach wird \(b\) aus dem Suffix entfernt. Genau diese Update-Reihenfolge erzwingt die Ordnung ohne Zusatzkorrektur.
1) Grundy-Tabelle. build_grundy(limit) berechnet alle Werte mit einem zeitgestempelten mex-Array.
2) Alphabetgröße. Danach bestimmt der Code das Maximum der auftretenden Grundy-Werte, um die Häufigkeitsarrays zu dimensionieren.
3) Suffix initialisieren. Anfangs enthält das rechte Intervall alle Positionen \(0,\dots,N\).
4) Sweep über \(b\). Für jedes \(b\) wird erst das Präfix erweitert, dann \(\text{add}_b\) berechnet, dann das Suffix angepasst.
5) Checkpoints. Verifiziert werden
$$\texttt{solve(29)}=1160$$
und ein vollständiger brute-force-Abgleich bei \(N=40\).
6) Endwert. Für \(N=100000\) ergibt sich
$$2586528661783.$$
Die Grundy-Vorberechnung kostet etwa \(O(N\sqrt N)\), weil für jedes \(n\) alle Quadrate bis \(n\) betrachtet werden. Die Zählphase kostet \(O(N\cdot G)\), wobei \(G\) die Zahl verschiedener Grundy-Werte ist und in der Praxis klein bleibt. Speicher: \(O(N+G)\).
Nim Square oyununda bir yığından, onu aşmayan herhangi bir pozitif kare \(k^2\) çıkarılabilir. Amaç,
$$0\le a\le b\le c\le N$$
koşulunu sağlayan üçlülerden kaç tanesinin kaybeden konum olduğunu saymaktır.
Bir yığındaki hamleler
$$n\to n-1,\ n-4,\ n-9,\dots$$
şeklindedir. Bu yüzden
$$g(0)=0,$$
$$g(n)=\operatorname{mex}\{g(n-k^2):k^2\le n\}$$
bağıntısı elde edilir.
Üç yığın oyunu, üç bağımsız impartial game'in ayrık toplamıdır. Dolayısıyla bir üçlü tam ve ancak şu durumda kaybedendir:
$$g(a)\oplus g(b)\oplus g(c)=0.$$
İlk tek-yığın değerleri
$$g(0..4)=(0,1,0,1,2)$$
şeklindedir. Örneğin
$$g(1)=\operatorname{mex}\{0\}=1,\qquad g(2)=\operatorname{mex}\{1\}=0,\qquad g(4)=\operatorname{mex}\{1,0\}=2.$$
\(N=4\) için toplam 12 kaybeden üçlü vardır; bunlar arasında \((0,0,0)\), \((0,1,1)\), \((1,2,3)\), \((2,2,2)\) gibi örnekler bulunur.
Tüm \((a,b,c)\) üçlülerini doğrudan dolaşmak
$$O(N^3)$$
zaman gerektirir. \(N=100000\) için bu imkansızdır.
Orta yığın \(b\) sabitlensin. O zaman
$$0\le a\le b,\qquad b\le c\le N.$$
Şu frekans dizilerini tanımlayalım:
$$\text{pref}[x]=\#\{a\le b:g(a)=x\},$$
$$\text{suf}[y]=\#\{c\ge b:g(c)=y\}.$$
Kaybetme koşulu
$$g(a)\oplus g(b)\oplus g(c)=0$$
olduğundan, \(x=g(a)\) için gerekli sağ taraftaki Grundy değeri
$$g(c)=x\oplus g(b)$$
olur. Böylece sabit \(b\)'nin katkısı
$$\text{add}_b=\sum_x \text{pref}[x]\cdot \text{suf}[x\oplus g(b)]$$
şeklindedir.
Kod önce \(g(b)\)'yi prefix tarafına ekler. Bu yüzden sayım anında prefix gerçekten \(a\in[0,b]\) aralığını temsil eder. Aynı anda suffix hâlâ \(c\in[b,N]\) aralığını temsil eder. Sayım bittikten sonra \(b\), suffix'ten çıkarılır. Yani eşitsizlikler, veri yapılarının güncellenme sırasına gömülüdür; ayrıca düzeltme faktörü gerekmez.
1) Grundy tablosu. build_grundy(limit), timestamp tabanlı bir mex dizisiyle tüm tek-yığın değerlerini üretir.
2) Grundy alfabesi boyutu. Sonra kod, ortaya çıkan maksimum Grundy değerini bulup frekans dizilerinin boyutunu belirler.
3) Suffix başlangıcı. Başta sağ taraf \(0,\dots,N\) aralığının tamamını içerir.
4) \(b\) üzerinden sweep. Her \(b\) için önce prefix güncellenir, sonra \(\text{add}_b\) toplanır, sonra suffix ayarlanır.
5) Checkpoint'ler. C++ sürümü
$$\texttt{solve(29)}=1160$$
değerini ve \(N=40\) için tam brute-force karşılaştırmasını doğrular.
6) Nihai Project Euler cevabı. \(N=100000\) için sonuç
$$2586528661783$$
olarak döner.
Grundy tablosunu kurmak yaklaşık \(O(N\sqrt N)\) zaman alır; çünkü her \(n\) için tüm kare hamleleri kontrol edilir. Sayım sweep'i ise \(O(N\cdot G)\) sürer; burada \(G\), görülen farklı Grundy değeri sayısıdır ve pratikte küçüktür. Bellek kullanımı \(O(N+G)\)'dir.
En Nim Square, desde un montón de tamaño \(n\) se puede quitar cualquier cuadrado perfecto positivo \(k^2\le n\). Debemos contar cuántas ternas
$$0\le a\le b\le c\le N$$
son posiciones perdedoras.
Los movimientos posibles son
$$n\to n-1,\ n-4,\ n-9,\dots$$
de modo que
$$g(0)=0,$$
$$g(n)=\operatorname{mex}\{g(n-k^2):k^2\le n\}.$$
La posición total es la suma disjunta de tres juegos imparciales, así que una terna es perdedora exactamente cuando
$$g(a)\oplus g(b)\oplus g(c)=0.$$
Los primeros valores son
$$g(0..4)=(0,1,0,1,2).$$
Para \(N=4\) hay exactamente 12 ternas perdedoras. Este ejemplo deja claro que el verdadero problema no es la teoría de juegos, sino contar eficientemente todas las ternas con xor nulo.
Recorrer todas las ternas \((a,b,c)\) costaría
$$O(N^3),$$
lo cual es inviable para \(N=100000\).
Fijamos el montón central \(b\). Entonces
$$0\le a\le b,\qquad b\le c\le N.$$
Definimos
$$\text{pref}[x]=\#\{a\le b:g(a)=x\},$$
$$\text{suf}[y]=\#\{c\ge b:g(c)=y\}.$$
Como la condición perdedora es
$$g(a)\oplus g(b)\oplus g(c)=0,$$
si \(x=g(a)\), entonces debe cumplirse
$$g(c)=x\oplus g(b).$$
Por tanto, la contribución del valor fijo \(b\) es
$$\text{add}_b=\sum_x \text{pref}[x]\cdot \text{suf}[x\oplus g(b)].$$
Antes de contar para un \(b\), el código añade \(g(b)\) al prefijo. Durante el conteo, el prefijo representa exactamente \(a\in[0,b]\), mientras que el sufijo todavía representa \(c\in[b,N]\). Solo después se elimina \(b\) del sufijo. Así, la restricción de orden está incorporada en el orden de actualización.
1) Tabla de Grundy. build_grundy(limit) calcula todos los valores con una estructura de mex por marcas temporales.
2) Tamaño del alfabeto Grundy. Luego se calcula el máximo valor de Grundy observado para dimensionar los arreglos de frecuencias.
3) Inicialización del sufijo. Al principio, el lado derecho contiene todos los tamaños \(0,\dots,N\).
4) Barrido por \(b\). Para cada \(b\), se actualiza el prefijo, se suma \(\text{add}_b\) y finalmente se ajusta el sufijo.
5) Checkpoints. La versión en C++ verifica
$$\texttt{solve(29)}=1160$$
y además compara \(\texttt{solve(40)}\) con un brute force completo.
6) Valor final. Para \(N=100000\), la respuesta es
$$2586528661783.$$
La precalculación de Grundy cuesta aproximadamente \(O(N\sqrt N)\), porque para cada \(n\) se inspeccionan todos los cuadrados hasta \(n\). El barrido de conteo cuesta \(O(N\cdot G)\), donde \(G\) es el número de valores Grundy distintos y resulta pequeño en la práctica. La memoria es \(O(N+G)\).
在 Nim Square 中,每一步可以从大小为 \(n\) 的一堆中拿走任意一个不超过它的正平方数 \(k^2\)。题目要求统计满足
$$0\le a\le b\le c\le N$$
的三元组里,有多少是必败态。
单堆允许的操作是
$$n\to n-1,\ n-4,\ n-9,\dots$$
因此
$$g(0)=0,$$
$$g(n)=\operatorname{mex}\{g(n-k^2):k^2\le n\}.$$
整个局面是三个无偏子博弈的直和,所以三元组 \((a,b,c)\) 是必败态,当且仅当
$$g(a)\oplus g(b)\oplus g(c)=0.$$
前几个单堆 Grundy 值为
$$g(0..4)=(0,1,0,1,2).$$
当 \(N=4\) 时,必败三元组一共有 12 个。这个例子说明,难点不在 Grundy 理论本身,而在如何高效统计所有 xor 为 0 的有序三元组。
直接枚举所有 \((a,b,c)\) 的代价是
$$O(N^3),$$
对 \(N=100000\) 完全不可行。
固定中间值 \(b\) 后,有
$$0\le a\le b,\qquad b\le c\le N.$$
定义频数
$$\text{pref}[x]=\#\{a\le b:g(a)=x\},$$
$$\text{suf}[y]=\#\{c\ge b:g(c)=y\}.$$
由于必败条件是
$$g(a)\oplus g(b)\oplus g(c)=0,$$
若 \(x=g(a)\),则必须有
$$g(c)=x\oplus g(b).$$
因此固定 \(b\) 的贡献为
$$\text{add}_b=\sum_x \text{pref}[x]\cdot \text{suf}[x\oplus g(b)].$$
实现顺序非常关键。程序先把 \(g(b)\) 加入前缀,因此计数时前缀正好代表 \(a\in[0,b]\)。同时此时后缀仍然包含 \(c\in[b,N]\)。计数完成之后,才把 \(b\) 从后缀里移除。于是顺序约束完全由更新顺序自动保证。
1) 构造 Grundy 表。 build_grundy(limit) 使用带时间戳的 mex 数组计算全部单堆值。
2) 统计 Grundy 值范围。 然后找出出现过的最大 Grundy 值,以确定频数数组大小。
3) 初始化后缀。 初始时后缀包含所有堆大小 \(0,\dots,N\)。
4) 扫描中间下标。 对每个 \(b\),先更新前缀,再套用上式累加 \(\text{add}_b\),最后更新后缀。
5) 检查点。 C++ 版本验证了
$$\texttt{solve(29)}=1160$$
并把 \(\texttt{solve(40)}\) 与完整 brute force 比较。
6) 最终答案。 当 \(N=100000\) 时,程序返回
$$2586528661783.$$
Grundy 预处理大约是 \(O(N\sqrt N)\),因为每个 \(n\) 都要查看不超过它的所有平方数。计数扫描是 \(O(N\cdot G)\),其中 \(G\) 是不同 Grundy 值的个数,而在实践中 \(G\) 很小。空间复杂度为 \(O(N+G)\)。
В Nim Square из кучи размера \(n\) можно снять любой положительный квадрат \(k^2\le n\). Нужно посчитать, сколько троек
$$0\le a\le b\le c\le N$$
являются проигрышными позициями.
Разрешенные переходы имеют вид
$$n\to n-1,\ n-4,\ n-9,\dots$$
поэтому
$$g(0)=0,$$
$$g(n)=\operatorname{mex}\{g(n-k^2):k^2\le n\}.$$
Вся позиция — это дизъюнктная сумма трех impartial games. Следовательно, тройка проигрышна тогда и только тогда, когда
$$g(a)\oplus g(b)\oplus g(c)=0.$$
Первые значения равны
$$g(0..4)=(0,1,0,1,2).$$
Для \(N=4\) получается ровно 12 проигрышных троек. Это показывает, что главный вопрос — не в самих значениях Гранди, а в быстром подсчете всех xor-нулевых троек.
Прямой перебор всех \((a,b,c)\) имеет стоимость
$$O(N^3),$$
что невозможно при \(N=100000\).
Фиксируем среднюю кучу \(b\). Тогда
$$0\le a\le b,\qquad b\le c\le N.$$
Введем частоты
$$\text{pref}[x]=\#\{a\le b:g(a)=x\},$$
$$\text{suf}[y]=\#\{c\ge b:g(c)=y\}.$$
Из условия
$$g(a)\oplus g(b)\oplus g(c)=0$$
следует, что при \(x=g(a)\) нужно
$$g(c)=x\oplus g(b).$$
Поэтому вклад фиксированного \(b\) равен
$$\text{add}_b=\sum_x \text{pref}[x]\cdot \text{suf}[x\oplus g(b)].$$
Перед подсчетом для данного \(b\) код сначала добавляет \(g(b)\) в префикс. Значит, во время счета префикс уже соответствует \(a\in[0,b]\), а суффикс еще соответствует \(c\in[b,N]\). Только после этого \(b\) удаляется из суффикса. Поэтому условие порядка встроено прямо в порядок обновлений.
1) Таблица Гранди. build_grundy(limit) вычисляет все значения через timestamp-массив для mex.
2) Размер алфавита Гранди. Затем находится максимальное встреченное значение Гранди, чтобы задать размер частотных массивов.
3) Инициализация суффикса. Сначала правая сторона содержит все размеры \(0,\dots,N\).
4) Sweep по \(b\). Для каждого \(b\) сначала расширяется префикс, затем считается \(\text{add}_b\), затем обновляется суффикс.
5) Контрольные проверки. В C++ проверяются
$$\texttt{solve(29)}=1160$$
и точное совпадение \(\texttt{solve(40)}\) с brute-force.
6) Итоговое значение. Для \(N=100000\) программа возвращает
$$2586528661783.$$
Предвычисление Гранди требует примерно \(O(N\sqrt N)\), так как для каждого \(n\) рассматриваются все квадраты до \(n\). Этап подсчета стоит \(O(N\cdot G)\), где \(G\) — число различных значений Гранди, и на практике оно невелико. Память: \(O(N+G)\).
في Nim Square يمكن إزالة أي مربع كامل موجب \(k^2\le n\) من كومة حجمها \(n\). المطلوب عدّ عدد الثلاثيات
$$0\le a\le b\le c\le N$$
التي تمثل أوضاعًا خاسرة.
الحركات الممكنة هي
$$n\to n-1,\ n-4,\ n-9,\dots$$
ولذلك
$$g(0)=0,$$
$$g(n)=\operatorname{mex}\{g(n-k^2):k^2\le n\}.$$
الوضع الكلي هو مجموع منفصل لثلاث ألعاب حيادية. لذلك تكون الثلاثية خاسرة تمامًا عندما
$$g(a)\oplus g(b)\oplus g(c)=0.$$
أول القيم هي
$$g(0..4)=(0,1,0,1,2).$$
وعند \(N=4\) نجد 12 ثلاثية خاسرة بالضبط. يوضح هذا أن الصعوبة الحقيقية ليست في نظرية Grundy نفسها، بل في العد السريع لجميع ثلاثيات xor الصفرية.
الفحص المباشر لجميع \((a,b,c)\) يكلف
$$O(N^3),$$
وهو غير عملي عند \(N=100000\).
لنثبت الكومة الوسطى \(b\). عندئذ
$$0\le a\le b,\qquad b\le c\le N.$$
ونعرّف
$$\text{pref}[x]=\#\{a\le b:g(a)=x\},$$
$$\text{suf}[y]=\#\{c\ge b:g(c)=y\}.$$
وبما أن شرط الخسارة هو
$$g(a)\oplus g(b)\oplus g(c)=0,$$
فإذا كان \(x=g(a)\)، فلا بد أن
$$g(c)=x\oplus g(b).$$
إذًا تكون مساهمة هذا \(b\) هي
$$\text{add}_b=\sum_x \text{pref}[x]\cdot \text{suf}[x\oplus g(b)].$$
قبل الحساب عند قيمة \(b\)، يضيف الكود \(g(b)\) إلى prefix. لذلك أثناء العد يكون prefix ممثلًا تمامًا للفترة \(a\in[0,b]\)، بينما يظل suffix ممثلًا للفترة \(c\in[b,N]\). وبعد انتهاء العد فقط يُزال \(b\) من suffix. أي أن شرط الترتيب مدمج في ترتيب التحديثات نفسه.
1) بناء جدول Grundy. تحسب الدالة build_grundy(limit) جميع القيم باستخدام مصفوفة mex مع طابع زمني.
2) تحديد حجم قيم Grundy. بعد ذلك يُحسب أكبر Grundy ظهر، من أجل تحديد حجم مصفوفتَي التكرار.
3) تهيئة suffix. في البداية يحتوي الطرف الأيمن على جميع القيم من \(0\) إلى \(N\).
4) المسح على \(b\). لكل \(b\)، يُحدَّث prefix أولًا، ثم تُضاف مساهمة \(\text{add}_b\)، ثم يُحدَّث suffix.
5) نقاط التحقق. تتحقق نسخة ++C من أن
$$\texttt{solve(29)}=1160$$
كما تقارن \(\texttt{solve(40)}\) مع brute-force كامل.
6) القيمة النهائية. عندما \(N=100000\)، تعيد الخوارزمية
$$2586528661783.$$
حساب جدول Grundy يكلف تقريبًا \(O(N\sqrt N)\)، لأن كل \(n\) يفحص جميع المربعات التي لا تتجاوزه. أما مرحلة العد فتكلف \(O(N\cdot G)\)، حيث \(G\) هو عدد قيم Grundy المختلفة، وهو صغير عمليًا. الذاكرة المطلوبة هي \(O(N+G)\).