<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[rounakkumarsingh blogs]]></title><description><![CDATA[rounakkumarsingh blogs]]></description><link>https://blog.rounakkumarsingh.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 16 May 2026 08:44:45 GMT</lastBuildDate><atom:link href="https://blog.rounakkumarsingh.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Advent of Code 2025 — Day 5: Fresh Ingredients & Interval Logic]]></title><description><![CDATA[In this article of my series Advent of Code 2025, where I discuss my solutions to daily puzzle, and hope to get some amazing feedback from you guys about my solutions(or just anything), I discuss today’s puzzle. As usual this goes without saying that...]]></description><link>https://blog.rounakkumarsingh.dev/advent-of-code-2025-day-5-fresh-ingredients-and-interval-logic</link><guid isPermaLink="true">https://blog.rounakkumarsingh.dev/advent-of-code-2025-day-5-fresh-ingredients-and-interval-logic</guid><category><![CDATA[AdventOfCode2025]]></category><category><![CDATA[Advent of code 2025]]></category><dc:creator><![CDATA[Rounak Kumar Singh]]></dc:creator><pubDate>Fri, 05 Dec 2025 10:32:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1764921176517/7c9003fe-356b-4040-9ab2-0fe621c11772.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article of my series <a target="_blank" href="https://rounakkumarsingh.hashnode.dev/series/advent-of-code-2025">Advent of Code 2025</a>, where I discuss my solutions to daily puzzle, and hope to get some amazing feedback from you guys about my solutions(or just anything), I discuss today’s puzzle. As usual this goes without saying that <strong>DON’T READ AHAED, IT CONTAINS SPOILERs</strong>.</p>
<h1 id="heading-introduction">Introduction</h1>
<p>Today’s puzzle followed from yesterday’s forklift operations, the forklifts were free, and we used them to break though the wall. And know what, the elves found that they had a <em>cafeteria</em> all along. But you hear “At this rate, we won't have any time left to put the wreaths up in the dining hall!” coming from the kitchen. You go in to <em>investigate</em>. "If only we hadn't switched to the new inventory management system right before Christmas!" another Elf exclaims. You ask what's going on.</p>
<p>The elves can’t figure out which ingredients are <em>fresh</em> and which are <em>spoiled</em>. Good person that you are you thought of helping them. You asked them how does it work, they give you their entire database’s copy and that’s the puzzle input today</p>
<h2 id="heading-input-format">Input Format</h2>
<p>The database operates on <em>ingredient IDs</em>. It consists of a list of <em>fresh ingredient ID ranges</em>, a blank line, and a list of <em>available ingredient IDs</em>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764922223395/27bb757f-0ac2-493c-9d5b-b61ba1f4222c.png" alt class="image--center mx-auto" /></p>
<p>The fresh ID ranges are <em>inclusive</em>: the range <code>3-5</code> means that ingredient IDs <code>3</code>, <code>4</code>, and <code>5</code> are all <em>fresh</em>. The ranges can also <em>overlap</em>;(important point) an ingredient ID is fresh if it is in <em>any</em> range.</p>
<h1 id="heading-puzzle-1">Puzzle 1</h1>
<p>We have to find the number of ingredients which are <em>fresh</em>. This involves a simple membership check in each of the ranges. I know that it ain’t efficient as many intervals overlap and some searched are just useless, but I won’t do that here as it a necessity in the second puzzle and I will suggest implementations while discussing puzzle 2(and how this one could be improved)</p>
<p>In the given example above only 3 are fresh (<code>5</code>, <code>11</code> and <code>17</code>)</p>
<h2 id="heading-implementation">Implementation</h2>
<h3 id="heading-input">Input</h3>
<p>I used a <code>std::vector&lt;pair&gt;</code> to represent the list of ranges and a <code>std::set</code> to represent the set of ingredients IDs.</p>
<pre><code class="lang-cpp"><span class="hljs-built_in">vector</span>&lt;<span class="hljs-built_in">pair</span>&lt;<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>&gt;&gt; ranges;
<span class="hljs-built_in">set</span>&lt;<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>&gt; iids;
<span class="hljs-built_in">string</span> line;
<span class="hljs-keyword">while</span> (getline(<span class="hljs-built_in">cin</span>, line)) {
  <span class="hljs-keyword">if</span> (line.empty()) {
    <span class="hljs-keyword">break</span>;
  }
  <span class="hljs-keyword">auto</span> dash = line.find(<span class="hljs-string">'-'</span>);
  <span class="hljs-keyword">auto</span> a = stoull(line.substr(<span class="hljs-number">0</span>, dash));
  <span class="hljs-keyword">auto</span> b = stoull(line.substr(dash + <span class="hljs-number">1</span>));
  ranges.push_back({a, b});
}
<span class="hljs-keyword">while</span> (getline(<span class="hljs-built_in">cin</span>, line)) {
  <span class="hljs-keyword">if</span> (line.empty()) {
    <span class="hljs-keyword">break</span>;
  }
  iids.insert(stoull(line));
}
</code></pre>
<h3 id="heading-solution">Solution</h3>
<ul>
<li>Just check for each ingredient if it lies in <em>any</em> range.</li>
</ul>
<pre><code class="lang-cpp"><span class="hljs-keyword">int</span> ans = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> iid : iids) {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">auto</span> [a, b] : ranges) {
        <span class="hljs-keyword">if</span> (a &lt;= iid &lt;= b)
            ans += <span class="hljs-number">1</span>;
    }
}
<span class="hljs-built_in">cout</span> &lt;&lt; ans &lt;&lt; <span class="hljs-built_in">endl</span>;
</code></pre>
<h2 id="heading-complexity-analysis">Complexity Analysis</h2>
<h3 id="heading-input-1">Input</h3>
<p>Let the number of ranges is \(R\), number of ingredients IDs be \(I\) and maximum line length(maximum number of characters / digits per line) be \(L\)</p>
<h4 id="heading-reading-ranges">Reading Ranges</h4>
<p>Per line:</p>
<ul>
<li><p><code>getline</code> → \(O(L)\)</p>
</li>
<li><p><code>line.find('-')</code> → \(O(L)\)</p>
</li>
<li><p><code>line.substr(0, dash)</code> and <code>line.substr(dash + 1)</code> → each \(O(L)\) (they allocate and copy)</p>
</li>
<li><p><code>stoull(...)</code> on those substrings → \(O(\text{#digits}) ⊆ O(L)\)</p>
</li>
<li><p><code>ranges.push_back</code> → amortized \(O(1)\)</p>
</li>
</ul>
<p>Total: \(O(R\cdot4L)\)</p>
<h4 id="heading-reading-ingredients-ids">Reading Ingredients IDs</h4>
<p>Per line:</p>
<ul>
<li><p><code>getline</code> → \(O(L)\)</p>
</li>
<li><p><code>stoull(line)</code> → \(O(L)\)</p>
</li>
<li><p><code>iids.insert(...)</code> for <code>std::set</code> → \(O(\log \text{|iid|})\)</p>
</li>
</ul>
<p>Total insertion cost \(\log1 + \log2 + \dots \log(I - 1) = \log((I -1)!) \leq \log(I!) \in O(I\log I)\) (Because \(x! \leq x^x\))</p>
<p>Total: \(O(I\cdot 2L + I \log I)\)</p>
<h4 id="heading-combined">Combined</h4>
<p>Total cost: \(O(R \cdot 4L + I\cdot 2L + I \log I)\), or simply \(O(2L\cdot (2R + I) + I \log I)\)</p>
<p>Assuming \(L\)(line length) is bounded and small</p>
<h4 id="heading-improvements">Improvements</h4>
<p>Instead of a ordered set(<code>std::set</code>), if we used a Hash Set(<code>std::unordered_set</code>, we would get a average time of \(O(1)\) while insertion and hence, total time complexity: \(O(2L\cdot (2R + I) + I)\)</p>
<h3 id="heading-solution-1">Solution</h3>
<p>Double Loop, therefore: \(O(I\cdot R)\)</p>
<h3 id="heading-final">Final</h3>
<p>Total: \(O(2L\cdot (2R + I) + I + I \cdot R)\)</p>
<p>Also space: \(O(R + I)\)</p>
<h1 id="heading-puzzle-2">Puzzle 2</h1>
<p>The Elves would like to know <em>all</em> of the IDs that the <em>fresh ingredient ID ranges</em> consider to be <em>fresh</em>.(Just the count to be honest)</p>
<p>For a given range \([a, b]\) there are total \(b - a + 1\) elements in the range, but we can’t add this values for over every freaking range, as they are <strong><em>overlapping</em></strong>, so we have to remove this characteristic, and I will try my best to explain it here, but this problem is based on <a target="_blank" href="https://leetcode.com/problems/merge-intervals/">Leetcode - 56 - Merge Intervals</a>, and there are some great people who have explained the solution, you can always look at their solution or even <a target="_blank" href="https://leetcode.com/problems/merge-intervals/editorial/">the official editorial</a>.</p>
<h2 id="heading-intuition-and-logic">Intuition and Logic</h2>
<p>Before diving into the exact steps, let me build the intuition of the solution. Let me ask you which of the intervals can/should/need to be <strong><em>merged</em></strong> to remove <strong><em>overlappicity</em></strong>(if that’s a word) and which intervals should not interact with each other in this process of merging. Let me make a diagram for you to understand.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764926686682/fe1d4ae0-25df-478b-b56a-6cdd34c2f677.png" alt class="image--center mx-auto" /></p>
<p>Just think for a while and think which of these should be merged into one intervals, and which one would be left as it is.</p>
<p>Intervals 1, 2 and 3 will be merged and Interval 4 will be left as it is. What was the thing that decided which intervals will be merged? And what thing decided the range of these newly merged intervals?</p>
<p>Let me answer the first question, and I think the answer to the second question will be clear? The thing that decides is the <strong><em>starting point of interval</em></strong>. For two intervals, they’ll be merged if and only if either intervals’ start lie in the other. And the starting point of this newly formed interval will be the minimum of these intervals’ starting points. So if I start with the interval which starts at the earliest, and process each interval in order of their starting point, all the intervals that need to be merged would come next to each other. And the thing that decides the new endpoint(or range) of these intervals is — <strong><em>the ending points</em></strong>. Maximum of these will be the new endpoint.</p>
<p>So the first step should be to <strong>sort</strong> these intervals, and starting with first interval, whenever we encounter each interval, we first check if the start of this interval lies in the list of merged intervals’(initially empty) last entry(which is also an interval). If not, then insert to the list, as this is the new un-overlapping interval, this will be the new last entry. If it does overlap, update the list’s last entry’s end according to this.</p>
<h2 id="heading-solution-2">Solution</h2>
<ul>
<li><p>Sort the intervals according to their starting points</p>
</li>
<li><p>Process each interval</p>
</li>
<li><p>If the new list is empty or this interval does not overlap with list’s last interval, insert this interval</p>
</li>
<li><p>If it does overlap, update the list’s last interval’s endpoint</p>
</li>
</ul>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-built_in">vector</span>&lt;<span class="hljs-built_in">pair</span>&lt;<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>&gt;&gt;
<span class="hljs-title">merge</span><span class="hljs-params">(<span class="hljs-built_in">vector</span>&lt;<span class="hljs-built_in">pair</span>&lt;<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>&gt;&gt; &amp;intervals)</span> </span>{

  sort(intervals.begin(), intervals.end());

  <span class="hljs-built_in">vector</span>&lt;<span class="hljs-built_in">pair</span>&lt;<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>, <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>&gt;&gt; merged;

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">auto</span> &amp;interval : intervals) {
    <span class="hljs-comment">// if the list of merged intervals is empty or if the current</span>
    <span class="hljs-comment">// interval does not overlap with the previous, simply append it.</span>
    <span class="hljs-keyword">if</span> (merged.empty() || merged.back().second &lt; interval.first) {
      merged.push_back(interval);
    }
    <span class="hljs-comment">// otherwise, there is overlap, so we merge the current and previous</span>
    <span class="hljs-comment">// intervals.</span>
    <span class="hljs-keyword">else</span> {
      merged.back().second = max(merged.back().second, interval.second);
    }
  }
  <span class="hljs-keyword">return</span> merged;
}
</code></pre>
<h3 id="heading-implementation-1">Implementation</h3>
<p>We just use this function, and since these new intervals are independent and non overlapping, we can just individually count each of these intervals’ count and add them up</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span> ans = <span class="hljs-number">0</span>;
<span class="hljs-keyword">auto</span> final_interval = merge(ranges);
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">auto</span> v : final_interval) ans += v.second - v.first + <span class="hljs-number">1</span>;
<span class="hljs-built_in">cout</span> &lt;&lt; ans &lt;&lt; <span class="hljs-built_in">endl</span>;
</code></pre>
<h2 id="heading-complexity-analysis-1">Complexity Analysis</h2>
<h3 id="heading-merge-operation">Merge Operation</h3>
<ul>
<li><p>Time Complexity: Sorting + Merging → \(O(R \log R + R)\)</p>
</li>
<li><p>Space Complexity: Sorting + Merging → \(O(2R)\)(One for sorting and another as the merged intervals will be stored in a separate list)</p>
</li>
</ul>
<h3 id="heading-final-count-calculation">Final Count calculation</h3>
<ul>
<li>Time complexity: \(O(R)\)</li>
</ul>
<h3 id="heading-total">Total</h3>
<ul>
<li><p>Time complexity: \(O(2R + R\log R)\)</p>
</li>
<li><p>Space Complexity: \(O(2R)\)</p>
</li>
</ul>
<h1 id="heading-improvements-to-solution-of-puzzle-1">Improvements to Solution of Puzzle 1</h1>
<ul>
<li>Since the new list of intervals is sorted, we can do a <strong>binary search</strong>, to check if ingredient id is in the valid range.</li>
</ul>
<pre><code class="lang-cpp"><span class="hljs-keyword">int</span> ans = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> iid : iids) {
    <span class="hljs-keyword">int</span> lo = <span class="hljs-number">0</span>, hi = merged.size() - <span class="hljs-number">1</span>;

    <span class="hljs-keyword">while</span> (lo &lt;= hi) {
        <span class="hljs-keyword">int</span> mid = (lo + hi) / <span class="hljs-number">2</span>;
        <span class="hljs-keyword">auto</span> [a, b] = merged[mid];
        <span class="hljs-keyword">if</span> (iid &lt; a)
            hi = mid - <span class="hljs-number">1</span>;
        <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (iid &gt; b)
            lo = mid + <span class="hljs-number">1</span>;
        <span class="hljs-keyword">else</span> {
            ans++;
            <span class="hljs-keyword">break</span>;
        }
    }
}
</code></pre>
<ul>
<li>Improved final time complexity: \(O(2L\cdot (2R + I) + I + I \cdot \log R)\)</li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>This one looked chaotic at first glance, but the moment I recognized the interval pattern, it turned into a very comfortable problem. Days like these are fun because they use real interview-style thinking without unnecessary fluff</p>
<p>Signing off</p>
]]></content:encoded></item><item><title><![CDATA[Advent Of Code 2025 - Day 4]]></title><description><![CDATA[Introduction
Today’s puzzle was about grid traversal and simulating process. Let me setup the scenario.
We are there at the printing department. And we need the forklift for the commute process, but the forklifts are used by the elves for moving heav...]]></description><link>https://blog.rounakkumarsingh.dev/advent-of-code-2025-day-4</link><guid isPermaLink="true">https://blog.rounakkumarsingh.dev/advent-of-code-2025-day-4</guid><category><![CDATA[AdventOfCode2025]]></category><category><![CDATA[Advent of code 2025]]></category><dc:creator><![CDATA[Rounak Kumar Singh]]></dc:creator><pubDate>Thu, 04 Dec 2025 12:45:28 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Today’s puzzle was about grid traversal and simulating process. Let me setup the scenario.</p>
<p>We are there at the printing department. And we need the forklift for the commute process, but the forklifts are used by the elves for moving heavy rolls of wrapping paper. We need to optimize their workflow, so that the forklifts become free ASAP.</p>
<p>Now comes the important part, the paper rolls are arranged in a grid, and in the given representation, a paper roll is represented by <code>@</code>. For example,</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764849630860/7ea6fa8c-cae6-4da8-b3ec-aa188bdae847.png" alt /></p>
<p>In this grid a <em>forklift</em> can access/lift a paper roll if there are <strong><em>fewer than four</em></strong> in the eight adjacent positions. In the above example, the rolls that can be accessed are marked <code>x</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764849931719/f638d843-f66e-40d0-b8a1-98daad425ad9.png" alt /></p>
<h1 id="heading-puzzle-1">Puzzle 1</h1>
<p>First puzzle was quite simple simple, we simply had to count the number of liftable rolls. In the given example, it is \(13\).</p>
<p>Let me tell you a little bit about the adjacent positions. In a grid, for a position <code>(i, j)</code>, the adjacent positions are the following. Its the positions at units distance from that position in vertical or horizontal or diagonal direction. In the figure below for blue position, the green position are called <strong>adjancent</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764850328951/449af7e9-cc8d-4f1b-9b8e-0fc7f915ce1d.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-solution-and-implementation">Solution and Implementation</h2>
<p>We will simply check at each of the eight positions, that if they exist(they don’t for border elements) and if they are paper roll and count them, if that <code>count &lt; 4</code>, count it in ans.</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; grid.size(); ++i) {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; grid[<span class="hljs-number">0</span>].size(); ++j) {
      <span class="hljs-keyword">if</span> (grid[i][j] != <span class="hljs-string">'@'</span>)
        <span class="hljs-keyword">continue</span>;
      <span class="hljs-keyword">int</span> count =
          <span class="hljs-comment">// N</span>
          (i &gt;= <span class="hljs-number">1</span> &amp;&amp; grid[i - <span class="hljs-number">1</span>][j] == <span class="hljs-string">'@'</span>) +
          <span class="hljs-comment">// NW</span>
          (i &gt;= <span class="hljs-number">1</span> &amp;&amp; j &gt;= <span class="hljs-number">1</span> &amp;&amp; grid[i - <span class="hljs-number">1</span>][j - <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
          <span class="hljs-comment">// W</span>
          (j &gt;= <span class="hljs-number">1</span> &amp;&amp; grid[i][j - <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
          <span class="hljs-comment">// SW</span>
          (j &gt;= <span class="hljs-number">1</span> &amp;&amp; i &lt; grid.size() - <span class="hljs-number">1</span> &amp;&amp; grid[i + <span class="hljs-number">1</span>][j - <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
          <span class="hljs-comment">// S</span>
          (i &lt; grid.size() - <span class="hljs-number">1</span> &amp;&amp; grid[i + <span class="hljs-number">1</span>][j] == <span class="hljs-string">'@'</span>) +
          <span class="hljs-comment">// SE</span>
          (j &lt; grid[<span class="hljs-number">0</span>].size() - <span class="hljs-number">1</span> &amp;&amp; i &lt; grid.size() - <span class="hljs-number">1</span> &amp;&amp;
           grid[i + <span class="hljs-number">1</span>][j + <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
          <span class="hljs-comment">// E</span>
          (j &lt; grid[<span class="hljs-number">0</span>].size() - <span class="hljs-number">1</span> &amp;&amp; grid[i][j + <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
          <span class="hljs-comment">// NE  ← missing one</span>
          (i &gt;= <span class="hljs-number">1</span> &amp;&amp; j &lt; grid[<span class="hljs-number">0</span>].size() - <span class="hljs-number">1</span> &amp;&amp; grid[i - <span class="hljs-number">1</span>][j + <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>);
      <span class="hljs-keyword">if</span> (count &lt; <span class="hljs-number">4</span>)
        ans++; <span class="hljs-comment">// count as liftable</span>
    }
  }
</code></pre>
<h1 id="heading-puzzle-2">Puzzle 2</h1>
<blockquote>
<p>Now the Elves just need help accessing as much of the paper as they can.</p>
<p>Once a roll of paper can be accessed by a forklift, it can be <em>removed</em>. Once a roll of paper is removed, the forklifts might be able to access <em>more</em> rolls of paper, which they might also be able to remove. How many total rolls of paper could the Elves remove if they keep repeating this process?</p>
</blockquote>
<p>In simple words, we remove the removable ones, then remove more(if possible) until we are left with such situation, that we can’t remove anymore. In the above example, the simulation/solution is present <a target="_blank" href="https://adventofcode.com/2025/day/4#part2">here</a>.</p>
<h2 id="heading-solution">Solution</h2>
<p>We can’t remove the removable paper rolls on the first pass(where we are checking if they are removable or not) as that might hinder the verification of other rolls, instead we just <strong><em>mark</em></strong> them, and then after this pass, we remove them(just mark them <code>.</code>). And repeat this process, until nothing is marked in first pass</p>
<h2 id="heading-implementation">Implementation</h2>
<p>In my implementation, I used a list of positions that are supposed to be marked. When I have to mark them, I just push them in this list. If nothing is in the list after this pass we just stop the whole process, else we remove(marking them <code>.</code> in the grid) all the positions while also adding the list’s original size to the final solution.</p>
<pre><code class="lang-cpp">  <span class="hljs-keyword">int</span> final_ans = <span class="hljs-number">0</span>;
  <span class="hljs-built_in">list</span>&lt;<span class="hljs-built_in">pair</span>&lt;<span class="hljs-keyword">int</span>, <span class="hljs-keyword">int</span>&gt;&gt; positions;
  <span class="hljs-keyword">do</span> {
    positions.clear();
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; grid.size(); ++i) {
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; grid[<span class="hljs-number">0</span>].size(); ++j) {
        <span class="hljs-keyword">if</span> (grid[i][j] != <span class="hljs-string">'@'</span>)
          <span class="hljs-keyword">continue</span>;
        <span class="hljs-keyword">int</span> cnt =
            <span class="hljs-comment">// N</span>
            (i &gt;= <span class="hljs-number">1</span> &amp;&amp; grid[i - <span class="hljs-number">1</span>][j] == <span class="hljs-string">'@'</span>) +
            <span class="hljs-comment">// NW</span>
            (i &gt;= <span class="hljs-number">1</span> &amp;&amp; j &gt;= <span class="hljs-number">1</span> &amp;&amp; grid[i - <span class="hljs-number">1</span>][j - <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
            <span class="hljs-comment">// W</span>
            (j &gt;= <span class="hljs-number">1</span> &amp;&amp; grid[i][j - <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
            <span class="hljs-comment">// SW</span>
            (j &gt;= <span class="hljs-number">1</span> &amp;&amp; i &lt; grid.size() - <span class="hljs-number">1</span> &amp;&amp; grid[i + <span class="hljs-number">1</span>][j - <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
            <span class="hljs-comment">// S</span>
            (i &lt; grid.size() - <span class="hljs-number">1</span> &amp;&amp; grid[i + <span class="hljs-number">1</span>][j] == <span class="hljs-string">'@'</span>) +
            <span class="hljs-comment">// SE</span>
            (j &lt; grid[<span class="hljs-number">0</span>].size() - <span class="hljs-number">1</span> &amp;&amp; i &lt; grid.size() - <span class="hljs-number">1</span> &amp;&amp;
             grid[i + <span class="hljs-number">1</span>][j + <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
            <span class="hljs-comment">// E</span>
            (j &lt; grid[<span class="hljs-number">0</span>].size() - <span class="hljs-number">1</span> &amp;&amp; grid[i][j + <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>) +
            <span class="hljs-comment">// NE  ← missing one</span>
            (i &gt;= <span class="hljs-number">1</span> &amp;&amp; j &lt; grid[<span class="hljs-number">0</span>].size() - <span class="hljs-number">1</span> &amp;&amp; grid[i - <span class="hljs-number">1</span>][j + <span class="hljs-number">1</span>] == <span class="hljs-string">'@'</span>);
        <span class="hljs-keyword">if</span> (cnt &lt; <span class="hljs-number">4</span>) {
          final_ans++;
          positions.push_back({i, j});
        }
      }
    }
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">auto</span> [i, j] : positions)
      grid[i][j] = <span class="hljs-string">'.'</span>;
  } <span class="hljs-keyword">while</span> (positions.size() != <span class="hljs-number">0</span>);
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>These might not have been the most efficient solutions, but they are surely simple, and that also counts in software engineering. Most of the times, simplicity of the solutions matters mote than the premature optimizations/optimizations possible.</p>
<p>Signing off</p>
]]></content:encoded></item><item><title><![CDATA[Advent of Code 2025 - Day 3]]></title><description><![CDATA[SPOILERS AHEAD!!!! DON’T READ WITHOUT TRYING
Today’s Advent of Code puzzles were quite simple to come up with, the only issue/challenge that might come is about “implementation”
Puzzle 1
Deduced Problem: Given a decimal digits string num find the max...]]></description><link>https://blog.rounakkumarsingh.dev/advent-of-code-2025-day-3</link><guid isPermaLink="true">https://blog.rounakkumarsingh.dev/advent-of-code-2025-day-3</guid><category><![CDATA[Advent of code 2025]]></category><category><![CDATA[AdventOfCode2025]]></category><dc:creator><![CDATA[Rounak Kumar Singh]]></dc:creator><pubDate>Wed, 03 Dec 2025 06:43:43 GMT</pubDate><content:encoded><![CDATA[<p><strong>SPOILERS AHEAD!!!! DON’T READ WITHOUT TRYING</strong></p>
<p>Today’s Advent of Code puzzles were quite simple to come up with, the only issue/challenge that might come is about “implementation”</p>
<h1 id="heading-puzzle-1">Puzzle 1</h1>
<p>Deduced Problem: Given a decimal digits string <code>num</code> find the maximum number that can be made using exactly 2 digits of <code>num</code>, maintaining their relative order</p>
<h2 id="heading-intuition-and-logic">Intuition and Logic</h2>
<p>A simple brute force solution will involve iteration over <code>[0 … len(num) - 2]</code> with <code>i</code> as iterator and for each <code>i</code> we iterate over <code>[i + 1 … len(num) - 1]</code> with <code>j</code> as iterator to find maximum digit in <code>num[i+1:]</code>. Hence for each <code>num[i]</code> we have maximum in <code>num[i+1:]</code> as <code>num[j]</code> and therefore corresponding candidate for <code>num[i]</code> is made by <code>(i, j)</code>. We can do this for each <code>i</code> in <code>[0 … len(num) - 2]</code>. And from the candidates take the maximum result.</p>
<p>Time Complexity: \(\Theta(n^2)\)</p>
<h2 id="heading-improvement">Improvement</h2>
<p>For finding the maximum for each element in its suffix array instead of scanning the entire suffix array, we can maintain a <code>suffix_max</code> array, where <code>suffix_max[i]</code> is<br /><code>max(num[i], max in [i+1 … len(nums - 1)]</code><br />Where we set the last element same as the last element in num as it has no suffix array.<br />We can compute this <code>suffix_max</code> in a single pass(reverse one). And in another pass of <code>num</code>, we use <code>num[i]</code> and <code>suffix_max[i+1]</code> for making candidates and hence choosing the maximum.</p>
<h2 id="heading-implementation">Implementation</h2>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">max_joltage</span><span class="hljs-params">(<span class="hljs-built_in">string</span> bank)</span> </span>{
        <span class="hljs-function"><span class="hljs-built_in">vector</span>&lt;<span class="hljs-keyword">char</span>&gt; <span class="hljs-title">suffix_max</span><span class="hljs-params">(bank.size())</span></span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = bank.size() - <span class="hljs-number">1</span>; i &gt;= <span class="hljs-number">0</span>; --i) {
                <span class="hljs-keyword">if</span> (i == bank.size() - <span class="hljs-number">1</span>) {
                        suffix_max[i] = bank[i];
                }
                <span class="hljs-keyword">else</span> {
                        suffix_max[i] = max(suffix_max[i + <span class="hljs-number">1</span>], bank[i]);
                }
        }
        <span class="hljs-keyword">int</span> ans = INT_MIN;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; bank.size() - <span class="hljs-number">1</span>; ++i) {
                ans = max(ans, (bank[i] - <span class="hljs-string">'0'</span>) * <span class="hljs-number">10</span> + (suffix_max[i + <span class="hljs-number">1</span>] - <span class="hljs-string">'0'</span>));
        }
        <span class="hljs-keyword">return</span> ans;
}
</code></pre>
<h1 id="heading-puzzle-2">Puzzle 2</h1>
<p>Deduced Problem: Given a decimal digits string <code>num</code> find the maximum number that can be made using exactly 12 digits of <code>num</code>, maintaining their relative order</p>
<h2 id="heading-intuition-and-logic-1">Intuition and Logic</h2>
<p>I came up with a simple solution</p>
<p>Start at start of string, and then find a maximum number such that there are still enough elements left to make a string of size <code>12</code>. Continue that until size 12 string is formed</p>
<h2 id="heading-implementation-1">Implementation</h2>
<ol>
<li><p>start at <code>pos</code> = 0</p>
</li>
<li><p>loop over the count <code>remaining</code> that tells how many digits are left to select(initially 12 and goes till 0)</p>
</li>
<li><p>Find the position <code>last</code> such that we find max digit in <code>[pos … last]</code> and there are at least <code>remaining - 1</code> elements left to process</p>
</li>
<li><p>Find max in <code>[pos … last]</code> say at position <code>best_idx</code>.</p>
</li>
<li><p>Add that to result and set <code>pos = best_idx + 1</code>.</p>
</li>
<li><p>Repeat until <code>remaining = 0</code>.</p>
</li>
</ol>
<p>I share the solution for any <code>k</code>(that is number of digits I have to choose)</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-built_in">string</span> <span class="hljs-title">max_subsequence_of_length</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">string</span> &amp;num, <span class="hljs-keyword">int</span> k = <span class="hljs-number">12</span>)</span> </span>{
    <span class="hljs-keyword">int</span> n = (<span class="hljs-keyword">int</span>)num.size();
    <span class="hljs-keyword">if</span> (k &gt;= n) <span class="hljs-keyword">return</span> s;          <span class="hljs-comment">// if input shorter or equal, return it</span>
    <span class="hljs-built_in">string</span> res;
    res.reserve(k);

    <span class="hljs-keyword">int</span> pos = <span class="hljs-number">0</span>; <span class="hljs-comment">// next index we can pick from</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> remaining = k; remaining &gt; <span class="hljs-number">0</span>; --remaining) {
        <span class="hljs-comment">// last index we can pick so that there remain (remaining-1) chars after it</span>
        <span class="hljs-keyword">int</span> last = n - remaining;
        <span class="hljs-comment">// find maximum digit in s[pos..last]</span>
        <span class="hljs-keyword">char</span> best = <span class="hljs-string">'0'</span>;
        <span class="hljs-keyword">int</span> best_idx = pos;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = pos; i &lt;= last; ++i) {
            <span class="hljs-keyword">if</span> (num[i] &gt; best) {
                best = num[i];
                best_idx = i;
                <span class="hljs-keyword">if</span> (best == <span class="hljs-string">'9'</span>) <span class="hljs-keyword">break</span>; <span class="hljs-comment">// can't do better than '9'</span>
            }
        }
        res.push_back(best);
        pos = best_idx + <span class="hljs-number">1</span>;
    }
    <span class="hljs-keyword">return</span> res;
}
</code></pre>
<p>Time Complexity: \(\Theta(n \cdot k)\), in our case \(\Theta(12n)\).</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>At last, it was one where you had to think more about robust implementation rather than approach and intuition. Follow me on X <a target="_blank" href="https://x.com/singhrounakkumr">@singhrounakkumr</a>.</p>
<p><em>Signing Off</em></p>
]]></content:encoded></item><item><title><![CDATA[Advent of Code 2025 - Day 2]]></title><description><![CDATA[Hi guys, today was Day 2 of AoC 2025, and boy it was fun one
Puzzle 1
Deduced problem: Given a set of ranges in the form [a, b], we had to find sum of all possible invalid IDs in these ranges.
Invalid ID is an ID which is made only of some sequence o...]]></description><link>https://blog.rounakkumarsingh.dev/advent-of-code-2025-day-2</link><guid isPermaLink="true">https://blog.rounakkumarsingh.dev/advent-of-code-2025-day-2</guid><category><![CDATA[#advent-of-code]]></category><category><![CDATA[puzzle]]></category><category><![CDATA[puzzles]]></category><dc:creator><![CDATA[Rounak Kumar Singh]]></dc:creator><pubDate>Mon, 01 Dec 2025 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>Hi guys, today was Day 2 of AoC 2025, and boy it was fun one</p>
<h1 id="heading-puzzle-1">Puzzle 1</h1>
<p>Deduced problem: Given a set of ranges in the form <code>[a, b]</code>, we had to find sum of all possible <em>invalid IDs</em> in these ranges.</p>
<p><em>Invalid ID</em> is an ID which is made only of some sequence of digits repeated twice. For example, <code>55</code>(<code>5</code> twice), <code>6464</code> (<code>64</code> twice), and <code>123123</code> (<code>123</code> twice) would all be invalid IDs.</p>
<h2 id="heading-intuition-and-thoughts">Intuition and Thoughts</h2>
<p>Hmm, so the invalid numbers(say \(N\)) would be of the form \(N \rightarrow xx\), where \(x\) is a say \(k\) digits number, so \(N\) will have \(k\) digits and the value of \(N\) is given by</p>
<p>$$N = x + 10^k \cdot x = (10^k + 1) \cdot x$$</p><p>So, for \(N\) must be a multiple of \(10^k + 1\)</p>
<h3 id="heading-approach">Approach</h3>
<p>For a fixed \(k\), \(N\) is a \(2k\) digit number which is a multiple of \(m = 10^k + 1\)</p>
<p>So if we find all \(x\) such that \(x \cdot m\) is in the range, then we found the invalid ids which can be deduced from the following conditions</p>
<p>$$a \leq N \leq b \implies a \leq x \cdot m \leq b$$</p><p>which is from the problem only and,</p>
<p>$$10^{k-1} \leq x \leq 10^k - 1$$</p><p>since \(x\) is \(k\) digit number</p>
<h3 id="heading-solving-the-problem">Solving the problem</h3>
<p>Combining the two inequalities we get,</p>
<p>$$\max(10^{k-1}, \frac{a}{m}) \leq x \leq \min (10^k - 1, \frac{b}{m})$$</p><p>Since this we are dealing with integer calculation, I will make it more precise</p>
<p>$$\max(10^{k-1}, \lceil \frac{a}{m} \rceil) \leq x \leq \min (10^k - 1, \lfloor\frac{b}{m}\rfloor)$$</p><h2 id="heading-implementation">Implementation</h2>
<p>I used <code>__int128</code> data type for storing the sums, the values and everything, just because I wanted to be paranoid — definitely not needed</p>
<ol>
<li><p>I used a precomputed table to compute the masks value</p>
</li>
<li><p>To avoid data loss in extreme cases due to conversion between integers and doubles and ceiling them I instead do <code>(a + b - 1) / b</code> to compute \(\lceil\frac{a}{b}\rceil\)</p>
</li>
</ol>
<p>Steps:</p>
<ol>
<li><p><strong>Early Exit on Useless Cases</strong>:</p>
<ul>
<li><p>If (a &gt; b), exit early as there are no valid ranges.</p>
</li>
<li><p>If there are no even-length numbers within the range, exit early.</p>
</li>
</ul>
</li>
<li><p><strong>Consider Each Valid (k)</strong>: Identify each <code>k</code> such that a <code>2k</code> digit number lies within the range <code>[a, b]</code>.</p>
</li>
<li><p><strong>Compute</strong> <code>min_x</code> <strong>and</strong> <code>max_x</code>: Calculate <code>min_x</code> and <code>max_x</code> using the inequalities</p>
</li>
<li><p><strong>Check Existence of Numbers</strong>: Ensure numbers exist by checking <code>min_x &lt;= max_x</code>.</p>
</li>
<li><p><strong>Generate (N)</strong>: N can be generated by <code>x</code> in <code>[min_x, min_x + 1, ..., max_x])</code>.</p>
</li>
<li><p><strong>Sum the Values</strong>: Sum all <code>x</code> using basic arithmetic progression results and multiply by <code>mask</code> to get the final value.</p>
</li>
</ol>
<pre><code class="lang-cpp"><span class="hljs-function">__int128 <span class="hljs-title">find_invalid</span><span class="hljs-params">(__int128 a, __int128 b)</span> </span>{
  <span class="hljs-keyword">if</span> (a &gt; b)
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  <span class="hljs-keyword">int</span> digits_1 = count_digits(a); <span class="hljs-comment">// We count the number of digits in a &amp; b</span>
  <span class="hljs-keyword">int</span> digits_2 = count_digits(b);
  <span class="hljs-keyword">if</span> (digits_1 == digits_2 &amp;&amp; (digits_1 &amp; <span class="hljs-number">1</span>))
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  __int128 ans = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> k = (digits_1 + <span class="hljs-number">1</span>) / <span class="hljs-number">2</span>; <span class="hljs-number">2</span> * k &lt;= digits_2; ++k) {
    <span class="hljs-keyword">int</span> twice_k = <span class="hljs-number">2</span> * k;
    __int128 mask = <span class="hljs-number">1</span> + pow10_128[k]; <span class="hljs-comment">// mask = 10^k + 1</span>
    __int128 loN = max(a, pow10_128[<span class="hljs-number">2</span> * k - <span class="hljs-number">1</span>]);
    __int128 hiN = min(b, pow10_128[<span class="hljs-number">2</span> * k] - <span class="hljs-number">1</span>);
    <span class="hljs-keyword">if</span> (loN &gt; hiN)
      <span class="hljs-keyword">continue</span>;
    __int128 min_x = (loN + mask - <span class="hljs-number">1</span>) / mask;
    __int128 max_x = hiN / mask;
    <span class="hljs-keyword">if</span> (min_x &gt; max_x) <span class="hljs-keyword">continue</span>;
    __int128 sum_x = (max_x - min_x + <span class="hljs-number">1</span>) * (min_x + max_x) / <span class="hljs-number">2</span>;
    ans += sum_x * mask;
  }
  <span class="hljs-keyword">return</span> ans;
}
</code></pre>
<h2 id="heading-complexity-analysis">Complexity Analysis</h2>
<p>The time complexity is \(\Theta(d_b - d_a)\) or \(\Theta(\log \frac{b}{a})\) as the loop runs that many times</p>
<h1 id="heading-puzzle-2">Puzzle 2</h1>
<p>Deduced Problem: Same as last problem but definition of <em>Invalid ID</em> changes.</p>
<p>An ID is <em>invalid</em> if it is made only of some sequence of digits repeated <em>at least</em> twice.</p>
<h2 id="heading-intuition-and-thoughts-1">Intuition and Thoughts</h2>
<p>Using the same notations as above, here \(N \rightarrow xxxx(\dots n\text{ times})\), so digits of \(N\), \(d_N = k \cdot n\), where \(N\) is given by</p>
<p>$$N = x \cdot (1 + 10^k + 10^{2k} \dots 10^{(n-1)k}) = x \cdot M(n, k)$$</p><p>where \(M(n, k) \) is a <a target="_blank" href="https://en.wikipedia.org/wiki/Repunit">repunit</a>-like number, which is used to repeat a \(k\) digit number \(n\) times in order to get a \(d= k \cdot n\) digit number.</p>
<p>By concept of geometric progressions,</p>
<p>$$M(n, k) = \dfrac{10^{nk} - 1}{10^k - 1}$$</p><p>So to generate a \(d_N\) digit \(N\), the only thing we need is few \(k\) digit numbers \(x\), where \(k \mid n\)(\(k\) divides \(n\)) and \(k \ne n\) and they will generate \(N\)</p>
<p>So for a fixed \(d_N\) and \(k\), we calculate the possible values of \(x\)(just like we did last time), but this time mask is replaced by a more general term <code>repunit</code> (mask is <code>repunit</code> for n = 2)</p>
<p>So this is simply solved like the previous one only the mask value is swapped.</p>
<p><img src="https://imgflip.com/i/adtp2r" alt class="image--center mx-auto" /></p>
<h2 id="heading-gotcha">Gotcha!!!</h2>
<p>This time there is an issue, the <strong><em>issue of duplicates</em></strong>, consider the following example<br />\(d_N = 6\), \(k = 1\), \(n = 6\), generates \(111111\)<br />which is also generated by \(k = 2, n = 3\) and \(k = 3 , n = 2\)</p>
<p>So there are solutions to this problem, I will share 3 and discuss only one and the simplest one and leave the other two as extensions for you to solve</p>
<h2 id="heading-solution">Solution</h2>
<p>Implementation quirks:</p>
<ol>
<li><p>I stored the proper factors of numbers upto 20 in a table named <code>DIV</code></p>
</li>
<li><p>Created a hash set for <code>__int128</code> type(easier than it sounds)</p>
</li>
</ol>
<p>Steps:</p>
<ol>
<li><p>Use the same procedure as the last puzzle</p>
</li>
<li><p>Instead of summing all the numbers at once, we will store each of the generated number in a hash set, so that we can <em>deduplicate</em> the duplicates</p>
</li>
<li><p>After going through all possible digits, we sum at last</p>
</li>
</ol>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">__int128_t</span> <span class="hljs-title">find_invalid</span><span class="hljs-params">(__int128 a, __int128 b)</span> </span>{
  <span class="hljs-keyword">if</span> (a &gt; b)
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  <span class="hljs-keyword">int</span> digits_1 = count_digits(a); <span class="hljs-comment">// We count the number of digits in a &amp; b</span>
  <span class="hljs-keyword">int</span> digits_2 = count_digits(b);
  <span class="hljs-built_in">unordered_set</span>&lt;__int128, Hash128, Eq128&gt; invalid_nums;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> digits = digits_1; digits &lt;= digits_2; ++digits) {

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> k : DIV[digits]) {
      __int128 repunit = (pow10_128[digits] - <span class="hljs-number">1</span>) / (pow10_128[k] - <span class="hljs-number">1</span>);
      __int128 loN = max(a, pow10_128[digits - <span class="hljs-number">1</span>]);
      __int128 hiN = min(b, pow10_128[digits] - <span class="hljs-number">1</span>);
      __int128 min_x = (loN + repunit - <span class="hljs-number">1</span>) / repunit;
      __int128 max_x = (hiN) / repunit;
      <span class="hljs-keyword">if</span> (min_x &gt; max_x)
        <span class="hljs-keyword">continue</span>;
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = min_x; i &lt;= max_x; ++i) {
        invalid_nums.insert(i * repunit);
      }
    }
  }
  <span class="hljs-keyword">__int128_t</span> ans = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> <span class="hljs-keyword">__int128_t</span> invalid_num : invalid_nums) {
    ans += invalid_num;
  }
  <span class="hljs-keyword">return</span> ans;
}
</code></pre>
<h2 id="heading-performance-analysis">Performance Analysis</h2>
<p>Outer loop runs \(\Theta(d_b - d_a)\) just like last puzzle<br />First Inner loop runs \(\Theta(f)\)times where \(f\) is the sum of number of proper factors of all \(d \in [d_a, d_b]\)<br />Second Inner loop runs \(\Theta(s)\) in total where \(s\) is the number of solutions(Invalid IDs) and so does the sum computing loop</p>
<p>Total time complexity: \(\Theta(d_b - d_a +f +s)\)</p>
<h2 id="heading-improvement-1-primitive-block">Improvement 1 — primitive block</h2>
<p>My initial idea for improvement is phrased by an LLM as:</p>
<p>Define a <code>k</code>-digit block <code>x</code> as <strong>primitive</strong> if it is <strong>not</strong> itself a repetition of a smaller block. For a given <code>(k,n)</code>, you should only accept <code>x</code> that are primitive; then every final <code>N</code> has a unique representation (with <code>k</code> minimal).</p>
<h2 id="heading-improvement-2-counting-primitives-without-enumerating-x-mobius">Improvement 2 - counting primitives without enumerating <code>x</code> (Möbius)</h2>
<p>I found the following from ChatGPT and haven’t explored much, so I would love to hear more about this from anyone of you</p>
<p>If you need to <em>count</em> how many primitive <code>k</code>-digit <code>x</code> lie in the interval <code>[A, B]</code> (where <code>A</code> and <code>B</code> are arbitrary, e.g. <code>x_low..x_high</code>), you can use inclusion-exclusion / Möbius inversion on divisors of <code>k</code>. Rough sketch:</p>
<ul>
<li>Let <code>F(t)</code> be number of <code>k</code>-digit numbers that are repetition of a block of length <code>t</code> where <code>t | k</code> (and <code>t&lt;k</code>). Those <code>x</code> are of the form <code>y</code> repeated <code>k/t</code> times. Counting those ≤ X reduces to counting <code>y ≤ something</code>. Use Möbius to invert and get count of primitive numbers. Implementation is trickier because of the arbitrary interval endpoints but doable if you need asymptotic speed and <code>k</code> can be large.</li>
</ul>
<p>For those of you who want the solution with improvements: <a target="_blank" href="https://gist.github.com/rounakkumarsingh/d8ed1af840c7ad995329e647672cc3e9">https://gist.github.com/rounakkumarsingh/d8ed1af840c7ad995329e647672cc3e9</a>. (I neither have written this nor have read this, this is generated by ChatGPT)</p>
]]></content:encoded></item></channel></rss>