Problem Summary

A beaver moves on the infinite integer line. At every step it inspects only the two cells \(x\) and \(x+1\), where \(x\) is its current position. Depending on whether those cells contain bananas, it removes a banana, moves a banana one cell left, or, if both cells are empty and it still carries at least three bananas, drops three bananas at \(x-1,x,x+1\) and jumps two cells left.

The requested function \(\operatorname{BB}(N)\) is the final position when the beaver starts at \(0\) carrying \(N\) bananas and the line is initially empty. The official check value is

$$\operatorname{BB}(1000)=1499.$$

The direct state space is infinite because the line is unbounded and \(N=10^{18}\) is far too large for step-by-step simulation. The solution below reduces the game to a finite universal simulation and then uses an eventual affine period in a threshold sequence.

Mathematical Approach

1. Conservation Law

Let \(C\) be the number of bananas carried by the beaver and let \(L\) be the number of bananas currently lying on the number line. Every rule preserves the total number of bananas:

$$C+L=N.$$

Rules that pick up a banana decrease \(L\) by \(1\) and increase \(C\) by \(1\). The rule that moves a banana from \(x+1\) to \(x\) keeps \(L\) unchanged. The dropping rule decreases \(C\) by \(3\) and increases \(L\) by \(3\). Hence the carried count never needs to be stored explicitly if we know \(N\) and \(L\).

2. When Does a Game with \(N\) Bananas Stop?

The game can stop only at an empty-pair event, meaning that there is no banana at either \(x\) or \(x+1\). At such an event the beaver checks whether \(C \ge 3\). Using the invariant, this is

$$N-L\ge 3.$$

Therefore the game stops precisely when

$$N-L<3 \quad\Longleftrightarrow\quad L\ge N-2.$$

This is the key reduction: instead of simulating a separate game for every \(N\), simulate a single beaver that always performs the three-banana drop, and record the first position at which the line contains at least a specified number of bananas.

3. Universal Simulator and Threshold Function

Define \(F(t)\) to be the current position \(x\) at the first empty-pair event for which the number \(L\) of bananas on the line is at least \(t\). Because a game with \(N\) bananas stops at the first empty-pair event with \(L\ge N-2\), we have

$$\boxed{\operatorname{BB}(N)=F(\max(0,N-2)).}$$

The code computes this function with Simulator::first_positions. Whenever an empty-pair event is reached, the current \(L\) may skip several thresholds, so all still-unfilled entries up to \(L\) receive the same position \(x\). This is why the implementation uses a loop

$$\text{while filled} < \min(L,T):\quad F(\text{filled}+1)=x.$$

The simulated line is stored as a Boolean array with a large offset. The helper functions set and clear update the array and maintain \(L\) exactly.

4. Empirical Period as a Finite Certificate

After a transient prefix the threshold sequence becomes affine-periodic. The constants used by the program are

$$a=512,\qquad p=71,\qquad s=118.$$

For every checked threshold \(m\) in the range

$$512\le m\le 10000-71,$$

the program verifies

$$\boxed{F(m+71)=F(m)+118.}$$

This is stronger than checking only the final answer: it checks the whole post-transient segment generated by the finite simulation. Conceptually, this is a cycle in the normalized local configuration: after \(71\) additional line bananas, the same local pattern reappears shifted by \(118\) cells.

5. Extrapolating to \(10^{18}\)

Let

$$t=\max(0,N-2).$$

If \(t\) lies inside the precomputed table, the answer is simply \(F(t)\). Otherwise write

$$q=\left\lfloor {t-a\over p}\right\rfloor,\qquad r=a+((t-a)\bmod p).$$

Repeatedly applying the affine-periodic identity gives

$$\boxed{\operatorname{BB}(N)=F(r)+q\,s.}$$

For the target \(N=10^{18}\), the code uses \(t=10^{18}-2\), \(q=14084507042253513\), and \(r=575\). The stored table supplies \(F(r)\), and the final decimal value is printed by the program.

6. Worked Checkpoint: \(N=1000\)

Here \(t=N-2=998\). The period formula gives

$$q=\left\lfloor {998-512\over 71}\right\rfloor=6,\qquad r=512+((998-512)\bmod 71)=572.$$

The finite simulator gives \(F(572)=791\). Therefore

$$F(998)=F(572)+6\cdot 118=791+708=1499,$$

which matches the official checkpoint.

How the Code Works

The C++ program first builds \(F(0),F(1),\dots,F(10000)\). It then runs small correctness checkpoints: \(\operatorname{BB}(0)=\operatorname{BB}(1)=\operatorname{BB}(2)=0\), \(\operatorname{BB}(3)=1\), \(\operatorname{BB}(5)=-1\), and \(\operatorname{BB}(1000)=1499\). It also checks the affine period \(F(m+71)=F(m)+118\) throughout the post-transient range.

The Python and Java versions use the same constants, the same threshold table, and the same extrapolation formula. The only implementation-level difference is numeric representation: Python integers are arbitrary precision, Java uses long, and C++ prints a __int128_t value through a small decimal conversion helper.

Complexity Analysis

Let \(T=10000\) be the table limit used by the implementation. The universal simulation is finite and stores \(O(T)\) cells in the Boolean window. Once the table and the period check are complete, a query for any \(N\), including \(10^{18}\), is answered by a constant number of integer operations.

Thus the target computation has fixed precomputation cost and \(O(1)\) extrapolation time. A naive simulation up to \(N=10^{18}\) would be infeasible because it would need to wait for an enormous number of drop and pickup events.

References

  1. Problem page: Project Euler 993
  2. Finite-state cycle detection: Wikipedia - Cycle detection
  3. Cellular automata and local update rules: Wikipedia - Cellular automaton

Problemzusammenfassung

Ein Biber bewegt sich auf der unendlichen ganzzahligen Geraden. In jedem Schritt betrachtet er nur die zwei Felder \(x\) und \(x+1\), wobei \(x\) seine aktuelle Position ist. Je nach Belegung dieser Felder entfernt er eine Banane, verschiebt eine Banane um ein Feld nach links oder legt, falls beide Felder leer sind und er noch mindestens drei Bananen trägt, drei Bananen auf \(x-1,x,x+1\) ab und springt zwei Felder nach links.

Die Funktion \(\operatorname{BB}(N)\) bezeichnet die Endposition, wenn der Biber bei \(0\) mit \(N\) getragenen Bananen startet und die Gerade anfangs leer ist. Der offizielle Kontrollwert lautet

$$\operatorname{BB}(1000)=1499.$$

Eine direkte Simulation des Zielwerts ist nicht sinnvoll: Die Gerade ist unbegrenzt, und \(N=10^{18}\) ist zu groß. Die Lösung verwendet deshalb eine endliche universelle Simulation und eine schließlich affine Periode in einer Schwellenwertfolge.

Mathematischer Ansatz

1. Erhaltungssatz

Sei \(C\) die Zahl der vom Biber getragenen Bananen und \(L\) die Zahl der Bananen auf der Geraden. Jede Regel erhält die Gesamtzahl

$$C+L=N.$$

Beim Aufheben sinkt \(L\) um \(1\) und \(C\) steigt um \(1\). Beim Verschieben einer Banane bleibt \(L\) gleich. Beim Ablegen sinkt \(C\) um \(3\) und \(L\) steigt um \(3\). Daher muss der Code die getragenen Bananen nicht explizit speichern; \(N\) und \(L\) reichen aus.

2. Abbruchbedingung

Das Spiel kann nur bei einem Leer-Paar-Ereignis enden, also wenn weder bei \(x\) noch bei \(x+1\) eine Banane liegt. Dort prüft der Biber, ob \(C\ge 3\). Mit dem Erhaltungssatz ist das

$$N-L\ge 3.$$

Der Abbruch tritt also genau dann ein, wenn

$$N-L<3 \quad\Longleftrightarrow\quad L\ge N-2.$$

Das ist die zentrale Reduktion. Statt für jedes \(N\) ein eigenes Spiel zu simulieren, simuliert man einen einzigen Biber, der den Drei-Bananen-Zug immer ausführt, und notiert die erste Position, an der mindestens eine gegebene Zahl von Bananen auf der Geraden liegt.

3. Universelle Simulation und Schwellenfunktion

Definiere \(F(t)\) als die aktuelle Position \(x\) beim ersten Leer-Paar-Ereignis, bei dem die Zahl \(L\) der liegenden Bananen mindestens \(t\) ist. Für das ursprüngliche Spiel gilt dann

$$\boxed{\operatorname{BB}(N)=F(\max(0,N-2)).}$$

Die Methode first_positions berechnet diese Funktion. Bei einem Leer-Paar-Ereignis kann \(L\) mehrere Schwellen überspringen; deshalb werden alle noch nicht gefüllten Einträge bis \(L\) mit derselben Position \(x\) belegt. Die Gerade wird als boolesches Array mit Offset gespeichert, während set und clear die Belegung und \(L\) exakt aktualisieren.

4. Periode als endliches Zertifikat

Nach einem Anfangsbereich wird die Schwellenfolge affin-periodisch. Die Konstanten sind

$$a=512,\qquad p=71,\qquad s=118.$$

Für jeden geprüften Wert

$$512\le m\le 10000-71$$

bestätigt das Programm

$$\boxed{F(m+71)=F(m)+118.}$$

Das prüft nicht nur einen einzelnen Endwert, sondern den ganzen nachtransienten Abschnitt der Simulation. Anschaulich kehrt nach \(71\) zusätzlichen liegenden Bananen dieselbe lokale Konfiguration wieder, nur um \(118\) Felder verschoben.

5. Extrapolation auf \(10^{18}\)

Setze

$$t=\max(0,N-2).$$

Liegt \(t\) in der Tabelle, ist die Antwort \(F(t)\). Andernfalls schreibt man

$$q=\left\lfloor {t-a\over p}\right\rfloor,\qquad r=a+((t-a)\bmod p).$$

Durch wiederholte Anwendung der Periodenidentität folgt

$$\boxed{\operatorname{BB}(N)=F(r)+q\,s.}$$

Für \(N=10^{18}\) verwendet der Code \(t=10^{18}-2\), \(q=14084507042253513\) und \(r=575\). Der Tabellenwert \(F(r)\) wird aus der endlichen Simulation gelesen; die endgültige Dezimalzahl gibt das Programm aus.

6. Kontrollrechnung: \(N=1000\)

Hier ist \(t=N-2=998\). Die Periodenformel liefert

$$q=\left\lfloor {998-512\over 71}\right\rfloor=6,\qquad r=512+((998-512)\bmod 71)=572.$$

Die Simulation gibt \(F(572)=791\), also

$$F(998)=F(572)+6\cdot 118=791+708=1499,$$

genau wie im offiziellen Beispiel.

Funktionsweise des Codes

Das C++-Programm erzeugt zuerst \(F(0),F(1),\dots,F(10000)\). Danach werden kleine Kontrollfälle geprüft: \(\operatorname{BB}(0)=\operatorname{BB}(1)=\operatorname{BB}(2)=0\), \(\operatorname{BB}(3)=1\), \(\operatorname{BB}(5)=-1\) und \(\operatorname{BB}(1000)=1499\). Zusätzlich wird die affine Periode \(F(m+71)=F(m)+118\) im ganzen geprüften Bereich bestätigt.

Python und Java folgen derselben Struktur. Python nutzt beliebig große Ganzzahlen, Java bleibt mit long innerhalb des Wertebereichs, und C++ verwendet für die Ausgabe vorsichtshalber __int128_t.

Komplexitätsanalyse

Für den festen Tabellenrand \(T=10000\) benötigt die Simulation \(O(T)\) Speicher im booleschen Fenster und eine endliche Vorberechnung. Danach besteht eine Anfrage für beliebiges \(N\) nur noch aus wenigen Ganzzahloperationen.

Die Zielauswertung hat somit feste Vorberechnungskosten und \(O(1)\) Extrapolationszeit. Eine naive Simulation bis \(10^{18}\) wäre wegen der riesigen Zahl von Ereignissen nicht praktikabel.

Referenzen

  1. Aufgabe: Project Euler 993
  2. Zyklenerkennung: Wikipedia - Cycle detection
  3. Zelluläre Automaten und lokale Regeln: Wikipedia - Cellular automaton

Problem Özeti

Bir kunduz sonsuz tamsayı doğrusu üzerinde hareket eder. Her adımda yalnızca bulunduğu konum \(x\) ile \(x+1\) hücrelerine bakar. Bu iki hücrede muz olup olmamasına göre bir muzu alır, bir muzu bir hücre sola taşır ya da iki hücre de boşsa ve elinde en az üç muz varsa \(x-1,x,x+1\) konumlarına birer muz bırakıp iki hücre sola gider.

\(\operatorname{BB}(N)\), kunduzun \(0\) konumunda \(N\) muz taşıyarak ve doğru üzerinde hiç muz yokken başladığı oyunun bitiş konumudur. Verilen kontrol değeri

$$\operatorname{BB}(1000)=1499.$$

Doğrudan simülasyon hedef için uygun değildir: doğru sonsuzdur ve \(N=10^{18}\) çok büyüktür. Bu çözüm oyunu önce tek bir sonlu evrensel simülasyona indirger, ardından eşik dizisindeki nihai afin periyodu kullanır.

Matematiksel Yaklaşım

1. Korunum Yasası

Kunduzun taşıdığı muz sayısı \(C\), doğru üzerindeki muz sayısı \(L\) olsun. Bütün kurallar toplam muz sayısını korur:

$$C+L=N.$$

Muz alma kurallarında \(L\) bir azalır ve \(C\) bir artar. Muz taşıma kuralında \(L\) değişmez. Üç muz bırakma kuralında \(C\) üç azalır ve \(L\) üç artar. Bu nedenle kodun eldeki muz sayısını ayrıca tutması gerekmez; \(N\) ve \(L\) bilgisi yeterlidir.

2. Oyun Ne Zaman Biter?

Oyun ancak \(x\) ve \(x+1\) hücreleri boş olduğunda, yani boş-çift olayında bitebilir. Bu anda kunduz \(C\ge 3\) olup olmadığını kontrol eder. Korunumdan

$$C=N-L$$

olduğu için bitiş koşulu

$$N-L<3 \quad\Longleftrightarrow\quad L\ge N-2$$

şeklindedir. Temel indirgeme budur: Her \(N\) için ayrı oyun simüle etmek yerine, üç muz bırakma hamlesini her zaman yapan tek bir evrensel oyun simüle edilir ve doğru üzerindeki muz sayısı belli eşiklere ilk ulaştığında konum kaydedilir.

3. Eşik Fonksiyonu

\(F(t)\), doğru üzerindeki muz sayısı \(L\)'nin en az \(t\) olduğu ilk boş-çift olayındaki konum olsun. O zaman özgün problem için

$$\boxed{\operatorname{BB}(N)=F(\max(0,N-2)).}$$

first_positions fonksiyonu tam olarak bu \(F\) tablosunu üretir. Bir boş-çift olayında \(L\) birden fazla eşiği atlayabildiği için, henüz doldurulmamış bütün eşikler aynı \(x\) konumuyla doldurulur. Böylece \(F(t)\), \(L\ge t\) koşulunun ilk kez gerçekleştiği konumu saklar.

Doğru, büyük bir ofsetle kaydırılmış boolean dizi olarak tutulur. set ve clear yardımcıları hem hücre doluluğunu hem de \(L\) sayacını güncel tutar.

4. Sonlu Sertifika Olarak Periyot

Başlangıç geçişlerinden sonra eşik dizisi afin-periyodik davranır. Kodun kullandığı sabitler

$$a=512,\qquad p=71,\qquad s=118.$$

Program şu aralıktaki her \(m\) için

$$512\le m\le 10000-71$$

eşitliğini doğrular:

$$\boxed{F(m+71)=F(m)+118.}$$

Bu yalnızca son cevabı kontrol etmekten daha güçlüdür; geçiş bölgesi sonrasındaki bütün tablo parçasını sınar. Sezgisel olarak, doğru üzerinde \(71\) ek muz eşiği geçildikten sonra aynı yerel desen \(118\) hücre sağa kaymış olarak tekrar görünür.

5. \(10^{18}\) İçin Sıçrama

Önce

$$t=\max(0,N-2)$$

tanımlanır. \(t\) tablo içindeyse cevap doğrudan \(F(t)\)'dir. Değilse

$$q=\left\lfloor {t-a\over p}\right\rfloor,\qquad r=a+((t-a)\bmod p)$$

yazılır. Periyot özdeşliği tekrar tekrar uygulanınca

$$\boxed{\operatorname{BB}(N)=F(r)+q\,s}$$

elde edilir. Hedef \(N=10^{18}\) için kod \(t=10^{18}-2\), \(q=14084507042253513\) ve \(r=575\) değerlerini kullanır; son ondalık değeri program üretir.

6. Kontrol Örneği: \(N=1000\)

Bu durumda \(t=N-2=998\). Periyot ayrıştırması

$$q=\left\lfloor {998-512\over 71}\right\rfloor=6,\qquad r=512+((998-512)\bmod 71)=572$$

verir. Sonlu simülasyondan \(F(572)=791\) okunur. Böylece

$$F(998)=F(572)+6\cdot118=791+708=1499,$$

bu da problemde verilen kontrol değeriyle aynıdır.

Kod Nasıl Çalışır?

C++ kodu önce \(F(0),F(1),\dots,F(10000)\) tablosunu oluşturur. Ardından \(\operatorname{BB}(0)=\operatorname{BB}(1)=\operatorname{BB}(2)=0\), \(\operatorname{BB}(3)=1\), \(\operatorname{BB}(5)=-1\) ve \(\operatorname{BB}(1000)=1499\) kontrollerini yapar. Son olarak \(F(m+71)=F(m)+118\) periyodunu tüm kontrol aralığında doğrular.

Python ve Java sürümleri aynı sabitleri, aynı tabloyu ve aynı sıçrama formülünü kullanır. Python tamsayıları sınırsızdır; Java için long yeterlidir; C++ sürümü ise güvenli çıktı için __int128_t kullanır.

Karmaşıklık Analizi

Tablo sınırı \(T=10000\) sabittir. Evrensel simülasyon boolean pencere içinde \(O(T)\) hücre saklar ve sonlu bir ön hesaplama yapar. Tablo kurulduktan sonra herhangi bir \(N\) için cevap sabit sayıda tamsayı işlemiyle bulunur.

Bu yüzden hedef hesaplama sabit ön hazırlık maliyetine ve \(O(1)\) sıçrama zamanına sahiptir. Naif simülasyon \(10^{18}\) için pratik değildir; çünkü devasa sayıda alma, taşıma ve bırakma olayı beklenmek zorunda kalır.

Referanslar

  1. Problem sayfası: Project Euler 993
  2. Döngü tespiti: Wikipedia - Cycle detection
  3. Yerel güncelleme kuralları ve hücresel otomatlar: Wikipedia - Cellular automaton

Resumen del Problema

Un castor se mueve sobre la recta infinita de enteros. En cada paso observa solo las casillas \(x\) y \(x+1\), donde \(x\) es su posición actual. Según la presencia de bananas en esas dos casillas, recoge una banana, desplaza una banana una casilla a la izquierda o, si ambas casillas están vacías y todavía lleva al menos tres bananas, deja bananas en \(x-1,x,x+1\) y salta dos casillas a la izquierda.

La función \(\operatorname{BB}(N)\) es la posición final cuando el castor empieza en \(0\), lleva \(N\) bananas y la recta está inicialmente vacía. El valor de comprobación dado es

$$\operatorname{BB}(1000)=1499.$$

Simular directamente el caso \(N=10^{18}\) no es viable. La solución convierte el proceso en una simulación universal finita y luego aprovecha una periodicidad afín en una sucesión de umbrales.

Enfoque Matemático

1. Ley de Conservación

Sea \(C\) el número de bananas que lleva el castor y \(L\) el número de bananas que están en la recta. Todas las reglas conservan el total:

$$C+L=N.$$

Al recoger una banana, \(L\) disminuye en \(1\) y \(C\) aumenta en \(1\). Al mover una banana de \(x+1\) a \(x\), \(L\) no cambia. Al dejar tres bananas, \(C\) disminuye en \(3\) y \(L\) aumenta en \(3\). Por tanto, basta mantener el estado de la recta y el contador \(L\).

2. Condición de Parada

El juego solo puede terminar cuando \(x\) y \(x+1\) están vacías. En ese momento el castor necesita saber si todavía tiene \(C\ge 3\). Usando \(C=N-L\), la parada ocurre cuando

$$N-L<3 \quad\Longleftrightarrow\quad L\ge N-2.$$

Este criterio elimina la dependencia directa de \(N\). Se puede simular un único proceso que siempre ejecuta la regla de dejar tres bananas y registrar dónde se alcanza por primera vez cada umbral de \(L\).

3. Función de Umbral

Definimos \(F(t)\) como la posición \(x\) en el primer evento con las dos casillas vacías para el cual el número de bananas sobre la recta satisface \(L\ge t\). Entonces

$$\boxed{\operatorname{BB}(N)=F(\max(0,N-2)).}$$

La rutina first_positions construye esta tabla. Si un evento aumenta la información disponible hasta un valor \(L\) que supera varios umbrales, todos esos umbrales reciben la misma posición \(x\). La recta se guarda en un arreglo booleano desplazado por un offset grande.

4. Periodo Afín

Después de un prefijo transitorio, la tabla cumple una ley periódica afín. Las constantes son

$$a=512,\qquad p=71,\qquad s=118.$$

Para todos los \(m\) comprobados con

$$512\le m\le 10000-71,$$

el código verifica

$$\boxed{F(m+71)=F(m)+118.}$$

Esto funciona como un certificado finito de la estructura usada por la extrapolación: la misma configuración local reaparece desplazada \(118\) posiciones después de \(71\) umbrales adicionales.

5. Extrapolación

Sea

$$t=\max(0,N-2).$$

Si \(t\) está en la tabla, usamos \(F(t)\). En caso contrario escribimos

$$q=\left\lfloor {t-a\over p}\right\rfloor,\qquad r=a+((t-a)\bmod p).$$

La identidad periódica da

$$\boxed{\operatorname{BB}(N)=F(r)+q\,s.}$$

Para \(N=10^{18}\), el programa calcula \(t=10^{18}-2\), \(q=14084507042253513\) y \(r=575\), lee \(F(r)\) de la tabla y muestra el resultado decimal.

6. Ejemplo de Verificación

Con \(N=1000\), tenemos \(t=998\). Entonces

$$q=\left\lfloor {998-512\over 71}\right\rfloor=6,\qquad r=512+((998-512)\bmod 71)=572.$$

La simulación da \(F(572)=791\), y por tanto

$$F(998)=791+6\cdot118=1499,$$

como exige el enunciado.

Cómo Funciona el Código

Primero se construye la tabla \(F(0),\dots,F(10000)\). Luego se comprueban los casos pequeños \(\operatorname{BB}(0)=\operatorname{BB}(1)=\operatorname{BB}(2)=0\), \(\operatorname{BB}(3)=1\), \(\operatorname{BB}(5)=-1\) y \(\operatorname{BB}(1000)=1499\). También se comprueba la identidad periódica en todo el intervalo posterior al prefijo.

Las versiones en C++, Python y Java son deliberadamente paralelas: cambian solo los detalles de tipos numéricos y de estructura de arreglo, no el algoritmo matemático.

Análisis de Complejidad

Con el límite fijo \(T=10000\), la simulación usa \(O(T)\) memoria para la ventana booleana y un coste finito de precomputación. Una vez construida la tabla, cualquier \(N\) se resuelve en \(O(1)\) mediante la fórmula de extrapolación.

Referencias

  1. Página del problema: Project Euler 993
  2. Detección de ciclos: Wikipedia - Cycle detection
  3. Autómatas celulares: Wikipedia - Cellular automaton

问题概述

一只河狸在无限整数直线上移动。每一步它只观察当前位置 \(x\) 与 \(x+1\) 两个格子。根据这两个 格子中是否有香蕉,它会取走一根香蕉、把一根香蕉向左移动一格,或者在两个格子都为空且手中至少 还有三根香蕉时,在 \(x-1,x,x+1\) 各放一根香蕉,并向左跳两格。

\(\operatorname{BB}(N)\) 表示从位置 \(0\) 开始、手持 \(N\) 根香蕉且直线上初始没有香蕉时的 终止位置。题目给出的校验值为

$$\operatorname{BB}(1000)=1499.$$

对于 \(N=10^{18}\),逐步模拟不可行。本解法把问题化为一个有限的通用模拟,并利用阈值序列在 暂态之后出现的仿射周期。

数学方法

1. 守恒量

令 \(C\) 为河狸手中香蕉数,\(L\) 为直线上香蕉数。所有规则都保持总数不变:

$$C+L=N.$$

取走香蕉会使 \(L\) 减一、\(C\) 加一;移动香蕉不改变 \(L\);放下三根香蕉会使 \(C\) 减三、 \(L\) 加三。因此程序只需维护直线状态和 \(L\),不必单独维护 \(C\)。

2. 终止条件

游戏只能在 \(x\) 与 \(x+1\) 都为空时终止。此时需要判断 \(C\ge 3\)。由守恒量 \(C=N-L\), 终止条件为

$$N-L<3 \quad\Longleftrightarrow\quad L\ge N-2.$$

这就是核心化简:不必为每个 \(N\) 单独模拟,而是模拟一个总是执行三香蕉放置规则的通用过程, 并记录直线上香蕉数第一次达到每个阈值时的位置。

3. 阈值函数

定义 \(F(t)\) 为第一次出现空二元格事件且 \(L\ge t\) 时的当前位置 \(x\)。于是原问题满足

$$\boxed{\operatorname{BB}(N)=F(\max(0,N-2)).}$$

first_positions 计算的正是这个表。若某次事件使 \(L\) 一次越过多个阈值,那么这些 尚未填入的阈值都对应同一个位置 \(x\)。直线用带有大偏移量的布尔数组表示,setclear 同时维护格子占用与 \(L\)。

4. 仿射周期

经过有限暂态后,阈值序列满足仿射周期规律。程序使用的常数为

$$a=512,\qquad p=71,\qquad s=118.$$

对所有被检查的

$$512\le m\le 10000-71$$

程序验证

$$\boxed{F(m+71)=F(m)+118.}$$

这相当于一个有限证书:不是只验证最终答案,而是验证暂态之后整段表的平移结构。直观地说, 多经过 \(71\) 个阈值后,同一局部形态以向右平移 \(118\) 格的方式再次出现。

5. 外推到 \(10^{18}\)

$$t=\max(0,N-2).$$

若 \(t\) 在表中,则答案为 \(F(t)\)。否则写成

$$q=\left\lfloor {t-a\over p}\right\rfloor,\qquad r=a+((t-a)\bmod p).$$

反复使用周期恒等式可得

$$\boxed{\operatorname{BB}(N)=F(r)+q\,s.}$$

对于目标 \(N=10^{18}\),程序使用 \(t=10^{18}-2\)、 \(q=14084507042253513\)、\(r=575\),再从表中读取 \(F(r)\) 并输出最终十进制值。

6. 校验例子

当 \(N=1000\) 时,\(t=998\)。周期分解为

$$q=\left\lfloor {998-512\over 71}\right\rfloor=6,\qquad r=512+((998-512)\bmod 71)=572.$$

有限模拟给出 \(F(572)=791\),所以

$$F(998)=791+6\cdot118=1499,$$

与题目给出的校验值一致。

代码说明

C++ 程序先构造 \(F(0),F(1),\dots,F(10000)\)。随后检查小规模断言: \(\operatorname{BB}(0)=\operatorname{BB}(1)=\operatorname{BB}(2)=0\), \(\operatorname{BB}(3)=1\),\(\operatorname{BB}(5)=-1\),以及 \(\operatorname{BB}(1000)=1499\)。它还在整个后暂态区间检查 \(F(m+71)=F(m)+118\)。

Python 和 Java 版本保持同一数学结构。Python 整数无需考虑溢出;Java 的 long 足以容纳目标值;C++ 版本使用 __int128_t 进行稳妥的输出。

复杂度分析

表的固定上界为 \(T=10000\)。通用模拟在布尔窗口中使用 \(O(T)\) 空间,并只进行有限预计算。 一旦表和周期检查完成,任意 \(N\) 的查询只需常数次整数运算。

参考资料

  1. 题目页面:Project Euler 993
  2. 循环检测:Wikipedia - Cycle detection
  3. 元胞自动机:Wikipedia - Cellular automaton

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

Бобр движется по бесконечной целочисленной прямой. На каждом шаге он смотрит только на клетки \(x\) и \(x+1\), где \(x\) — его текущая позиция. В зависимости от наличия бананов он подбирает банан, переносит банан на одну клетку влево или, если обе клетки пусты и у него есть хотя бы три банана, кладет бананы в \(x-1,x,x+1\) и переходит на две клетки влево.

\(\operatorname{BB}(N)\) — это конечная позиция при старте из \(0\) с \(N\) бананами в руках и пустой прямой. Данный в задаче контрольный пример:

$$\operatorname{BB}(1000)=1499.$$

Для \(N=10^{18}\) прямое моделирование невозможно. Решение строит конечную универсальную симуляцию и использует аффинную периодичность последовательности порогов.

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

1. Закон Сохранения

Пусть \(C\) — число бананов у бобра, а \(L\) — число бананов на прямой. Каждое правило сохраняет

$$C+L=N.$$

При подборе банана \(L\) уменьшается на \(1\), а \(C\) увеличивается на \(1\). Перенос банана не меняет \(L\). Выкладывание трех бананов уменьшает \(C\) на \(3\) и увеличивает \(L\) на \(3\). Поэтому достаточно знать конфигурацию прямой и \(L\).

2. Условие Остановки

Игра может остановиться только в событии пустой пары, когда в \(x\) и \(x+1\) нет бананов. Тогда проверяется условие \(C\ge 3\). Так как \(C=N-L\), остановка происходит ровно когда

$$N-L<3 \quad\Longleftrightarrow\quad L\ge N-2.$$

Это сводит все значения \(N\) к одной универсальной симуляции: мы всегда выполняем правило выкладывания трех бананов и записываем позицию первого достижения каждого порога по \(L\).

3. Пороговая Функция

Обозначим через \(F(t)\) позицию \(x\) в первом событии пустой пары, где \(L\ge t\). Тогда

$$\boxed{\operatorname{BB}(N)=F(\max(0,N-2)).}$$

Именно эту таблицу строит first_positions. Если текущее \(L\) перескакивает через несколько порогов, все эти пороги получают одну и ту же позицию \(x\). Состояние прямой хранится в булевом массиве со сдвигом, а операции set и clear поддерживают счетчик \(L\).

4. Аффинная Периодичность

После конечного префикса выполняется периодическое соотношение с сдвигом. Константы:

$$a=512,\qquad p=71,\qquad s=118.$$

Для каждого проверенного \(m\) из диапазона

$$512\le m\le 10000-71$$

код подтверждает

$$\boxed{F(m+71)=F(m)+118.}$$

Это проверка всей послепереходной части таблицы, а не только одного конечного значения. Интуитивно та же локальная конфигурация появляется снова после \(71\) дополнительных банановых порогов, но со сдвигом на \(118\) клеток.

5. Экстраполяция

Положим

$$t=\max(0,N-2).$$

Если \(t\) лежит в таблице, ответ равен \(F(t)\). Иначе пишем

$$q=\left\lfloor {t-a\over p}\right\rfloor,\qquad r=a+((t-a)\bmod p).$$

Тогда

$$\boxed{\operatorname{BB}(N)=F(r)+q\,s.}$$

Для \(N=10^{18}\) программа использует \(t=10^{18}-2\), \(q=14084507042253513\) и \(r=575\); затем берет \(F(r)\) из таблицы и печатает итоговое десятичное значение.

6. Проверочный Пример

Для \(N=1000\) имеем \(t=998\). Получаем

$$q=\left\lfloor {998-512\over 71}\right\rfloor=6,\qquad r=512+((998-512)\bmod 71)=572.$$

Симуляция дает \(F(572)=791\), значит

$$F(998)=791+6\cdot118=1499,$$

что совпадает с условием задачи.

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

Сначала строится таблица \(F(0),\dots,F(10000)\). Затем выполняются контрольные проверки: \(\operatorname{BB}(0)=\operatorname{BB}(1)=\operatorname{BB}(2)=0\), \(\operatorname{BB}(3)=1\), \(\operatorname{BB}(5)=-1\), \(\operatorname{BB}(1000)=1499\), а также период \(F(m+71)=F(m)+118\) на всем проверенном интервале.

Версии на C++, Python и Java используют один и тот же алгоритм. Отличаются только типы чисел и детали массивов: Python работает с произвольной точностью, Java использует long, а C++ печатает значение через __int128_t.

Анализ Сложности

При фиксированном пределе \(T=10000\) универсальная симуляция требует \(O(T)\) памяти в булевом окне и конечной предварительной работы. После этого запрос для любого \(N\) вычисляется за \(O(1)\).

Источники

  1. Страница задачи: Project Euler 993
  2. Поиск циклов: Wikipedia - Cycle detection
  3. Клеточные автоматы: Wikipedia - Cellular automaton

ملخص المسألة

يتحرك القندس على خط أعداد صحيح غير محدود. في كل خطوة ينظر فقط إلى الموضعين \(x\) و \(x+1\)، حيث \(x\) هو موضعه الحالي. بحسب وجود الموز في هذين الموضعين، قد يلتقط موزة، أو ينقل موزة خانة واحدة إلى اليسار، أو إذا كان الموضعان فارغين وما زال يحمل ثلاث موزات على الأقل، يضع موزة في كل من \(x-1,x,x+1\) ثم يتحرك خانتين إلى اليسار.

الدالة \(\operatorname{BB}(N)\) هي موضع النهاية عندما يبدأ القندس من \(0\) حاملا \(N\) موزة والخط خال من الموز. قيمة الاختبار المعطاة هي

$$\operatorname{BB}(1000)=1499.$$

المحاكاة المباشرة غير مناسبة عندما \(N=10^{18}\). لذلك نحول اللعبة إلى محاكاة كونية منتهية، ثم نستعمل دورية خطية مزاحة في متتالية العتبات.

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

1. قانون الحفظ

ليكن \(C\) عدد الموز الذي يحمله القندس، وليكن \(L\) عدد الموز الموجود على الخط. كل القواعد تحفظ المجموع:

$$C+L=N.$$

عند التقاط موزة ينقص \(L\) بواحد ويزيد \(C\) بواحد. نقل موزة من موضع إلى آخر لا يغير \(L\). أما وضع ثلاث موزات فينقص \(C\) بثلاثة ويزيد \(L\) بثلاثة. لذلك لا نحتاج إلى تخزين \(C\) صراحة؛ يكفي تتبع حالة الخط والعدد \(L\).

2. شرط التوقف

لا يمكن أن تتوقف اللعبة إلا عندما يكون الموضعان \(x\) و \(x+1\) فارغين. عندها يفحص القندس الشرط \(C\ge 3\). وبما أن \(C=N-L\)، فإن التوقف يحدث عندما

$$N-L<3 \quad\Longleftrightarrow\quad L\ge N-2.$$

هذه هي الفكرة الأساسية. بدلا من محاكاة لعبة مختلفة لكل \(N\)، نحاكي لعبة واحدة تستمر دائما في تطبيق قاعدة وضع ثلاث موزات، ونسجل أول موضع يصل فيه \(L\) إلى كل عتبة.

3. دالة العتبة

نعرف \(F(t)\) بأنه الموضع \(x\) في أول حدث تكون فيه الخانتان فارغتين ويكون \(L\ge t\). عندئذ

$$\boxed{\operatorname{BB}(N)=F(\max(0,N-2)).}$$

الدالة first_positions تبني هذا الجدول. إذا تجاوزت قيمة \(L\) عدة عتبات دفعة واحدة، فإن كل تلك العتبات تحصل على الموضع نفسه \(x\). يخزن الخط في مصفوفة منطقية مع إزاحة كبيرة، وتحافظ عمليتا set و clear على عدد الموز \(L\) بدقة.

4. الدورية الخطية المزاحة

بعد بادئة انتقالية قصيرة تصبح متتالية العتبات دورية مع إزاحة خطية. الثوابت هي

$$a=512,\qquad p=71,\qquad s=118.$$

لكل \(m\) مفحوص في المجال

$$512\le m\le 10000-71$$

يتحقق البرنامج من

$$\boxed{F(m+71)=F(m)+118.}$$

هذا ليس فحصا لقيمة نهائية واحدة فقط، بل فحص لجزء كامل من الجدول بعد المرحلة الانتقالية. ومعناه الحدسي أن النمط المحلي نفسه يعود بعد \(71\) عتبة إضافية، لكنه مزاح بمقدار \(118\) موضعا.

5. الاستقراء إلى \(10^{18}\)

لنضع

$$t=\max(0,N-2).$$

إذا كان \(t\) داخل الجدول، فالجواب هو \(F(t)\). وإلا نكتب

$$q=\left\lfloor {t-a\over p}\right\rfloor,\qquad r=a+((t-a)\bmod p).$$

وبتكرار هوية الدورية نحصل على

$$\boxed{\operatorname{BB}(N)=F(r)+q\,s.}$$

عند الهدف \(N=10^{18}\)، يستخدم البرنامج \(t=10^{18}-2\)، \(q=14084507042253513\)، و \(r=575\)، ثم يقرأ \(F(r)\) من الجدول ويطبع القيمة العشرية النهائية.

6. مثال التحقق

عندما \(N=1000\)، لدينا \(t=998\). لذلك

$$q=\left\lfloor {998-512\over 71}\right\rfloor=6,\qquad r=512+((998-512)\bmod 71)=572.$$

تعطي المحاكاة \(F(572)=791\)، ومن ثم

$$F(998)=791+6\cdot118=1499,$$

وهو يطابق قيمة الاختبار في المسألة.

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

يبني البرنامج أولا الجدول \(F(0),F(1),\dots,F(10000)\). ثم يفحص الحالات الصغيرة: \(\operatorname{BB}(0)=\operatorname{BB}(1)=\operatorname{BB}(2)=0\)، \(\operatorname{BB}(3)=1\)، \(\operatorname{BB}(5)=-1\)، و \(\operatorname{BB}(1000)=1499\). كما يفحص علاقة الدورية \(F(m+71)=F(m)+118\) على المجال كله.

نسخ C++ و Python و Java تستعمل البنية نفسها. Python يستعمل أعدادا صحيحة غير محدودة، Java يستعمل long، و C++ يستعمل __int128_t للإخراج الآمن.

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

مع الحد الثابت \(T=10000\)، تحتاج المحاكاة الكونية إلى ذاكرة \(O(T)\) في النافذة المنطقية وإلى حساب مسبق منته. بعد بناء الجدول، يحسب أي \(N\) بعدد ثابت من العمليات الصحيحة، أي بزمن \(O(1)\).

مراجع

  1. صفحة المسألة: Project Euler 993
  2. كشف الدورات: Wikipedia - Cycle detection
  3. الأتمتة الخلوية: Wikipedia - Cellular automaton