Count Palindromes
Difficulty: Hard

A string is made of only lowercase latin letters (a,b,c,d,.....,z). Can you find the length of the lexicographically smallest string such that it has exactly $K$ sub-strings, each of which are palindromes? 

Input Format:
The first line of input contains single integer $T$ - the number of testcases.  
T lines follow, each containing the integer $K$.


Output Format:
Output exactly $T$ lines. Each line should contain single integer - the length of the lexicographically smallest string.


Sample Input:
    2
    10
    17


Sample Output:
    4
    7


Python 3 starter code:
#
# Complete the 'solve' function below.
#
# The function is expected to return an INTEGER.
# The function accepts LONG_INTEGER k as parameter.
#

def solve(k):
    # Write your code here



Editorial: Count Palindromes - 101 Hack March Editorial
<style id="MathJax_SVG_styles">.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%}
.MathJax_SVG .MJX-monospace {font-family: monospace}
.MathJax_SVG .MJX-sans-serif {font-family: sans-serif}
.MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0}
.MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none}
.mjx-svg-href {fill: blue; stroke: blue}
</style><svg style="display: none;"><defs id="MathJax_SVG_glyphs"></defs></svg><p><a href="https://www.hackerrank.com/contests/101mar14/challenges/count-palindromes">Count Palindromes</a> <br>
<strong>Difficulty Level</strong> : Medium-Hard <br>
<strong>Problem Setter</strong> : <a href="https://www.hackerrank.com/seyaua">Levgen Soboliev</a>  <br>
<strong>Problem Tester</strong> : <a href="https://www.hackerrank.com/tmt514">Shang-En Huang
</a>  <br></p>

<p><strong>Solution</strong>  </p>

<p>Let the string s has X sub-strings, which are palindromes. Let's look at s+'a'. If it has more than K sub-strings, which are palindromes - let's look at s+'b'. The point is that if we start from empty string in such recursive way we will get the smallest lexicographically string which has exactly K palindromes. So, now we have a solution - just add the smallest possible symbol and maintain the total number of sub-strings which are palindromes no more than K. But this solution is slow. We need some clever observation. At first, if K is big - we will have a lot of 'a' at the beginning of resulting string. More precise we will have exactly S number of 'a' at the beginning of the resulting string, where S * (S + 1) / 2 &lt;= K. So, this part we can make using O(1) time. After that, if the difference Y = K - S * (S + 1) / 2 is big, than we will just add 'b' to resulting string and will have a lot 'a' again. If the difference Y is small, than we can just add the smallest possible symbol and count the number of new sub-strings which are palindromes. In each of this two cases we will get the difference between current number of sub-strings-palindromes less than 1000 and just go with simple recursive procedure to find next symbols.</p>

<p><strong>Setter's Code</strong></p>

<pre><code>#include &lt;iostream&gt;
#include &lt;cstdio&gt;
#include &lt;algorithm&gt;
#include &lt;set&gt;
#include &lt;map&gt;
#include &lt;vector&gt;
#include &lt;cmath&gt;
#include &lt;queue&gt;
#include &lt;bitset&gt;
#include &lt;ctime&gt;
#include &lt;string&gt;
#include &lt;cstring&gt;
#pragma comment(linker, "/STACK:256000000")

using namespace std;

const int maxN = 20000;
const int BOUND = 2000;

long long find_limit(long long k) {
 long long l = 0, r = 5000000;
 long long result = 0;
 while (l &lt;= r) {
   long long key = (l + r) / 2;
   long long total = (key * (key + 1)) / 2;
   if (total &lt;= k) {
     result = key;
     l = key + 1;
   } else {
     r = key - 1;
   }
 }
 return result;
}

char s[maxN];

void solvebig(long long k) {
 int MID = 10000;
 long long counta = find_limit(k);
 long long total = (counta * (counta + 1)) / 2;

 k -= total;

 if (k == 0) {
   cout &lt;&lt; counta &lt;&lt; endl;
   return;
 }
 if (k == 1) {
   cout &lt;&lt; counta + 1 &lt;&lt; endl;
   return;
 }

 MID = min(MID, (int)counta);
 for (int i = 0; i &lt; MID; ++i) {
   s[i] = 'a';
 }

 int res = counta;
 s[MID] = 'b';

 --k;

 bool addonly_a = true;
 for (int i = MID + 1; ; ++i) {
   for (char c = 'a'; c &lt;= 'z'; ++c) {
     s[i] = c;
     if (c != 'a') {
       addonly_a = false;
     }
     long long cur = 0;
     if (addonly_a) {
       cur = i - MID + 1;
     } else {
       int bound = min(MID, 2 * (i - MID + 10));
       bound = min(bound, i + 1);
       for (int j = 1; j &lt;= bound; ++j) {
         bool good = true;
         for (int k = 0; k &lt; j / 2; ++k) {
           if (s[i - k] != s[i - j + 1 + k]) {
             good = false;
             break;
           }
         }
         if (good) {
           ++cur;
         }
       }
     }
     if (cur == k) {
       cout &lt;&lt; counta + (i - MID + 1) &lt;&lt; endl;
       return;
     }
     if (cur &lt; k) {
       k -= cur;
       break;
     }
   }
 }
}

int main() {
 //freopen("input.txt", "r", stdin);
 //freopen("output2.txt", "w", stdout);

 int t;
 cin &gt;&gt; t;
 for (int i = 0; i &lt; t; ++i) {
   //cerr &lt;&lt; i &lt;&lt; endl;
   long long k;
   cin &gt;&gt; k;
   solvebig(k);
 }

 return 0;
}
</code></pre>

<p><strong>Tester's Code</strong></p>

<pre><code>//by tmt514
#include &lt;cstdio&gt;
#include &lt;cstring&gt;
#include &lt;cmath&gt;
#include &lt;algorithm&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;cassert&gt;
using namespace std;

#define FOR(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define SZ(c) ((int)(c).size())

typedef long long LL;

int main(void) {
    int T;
    scanf("%d", &amp;T);
    assert(1 &lt;= T &amp;&amp; T &lt;= 100);
    while(T--) {
        LL n;
        cin &gt;&gt; n;
        assert(1 &lt;= n &amp;&amp; n &lt;= 1e12);
        vector&lt;int&gt; B;
        B.push_back(0);
        int m=0;
        while(n&gt;0) {
            ++m;
            //try 'a'
            LL p = m-B.back();
            if(SZ(B)&gt;=2) p += (m-B.back() &lt;= B.back()-B[SZ(B)-2]-1);
            if(SZ(B)&gt;=3) p += (m-B.back() &lt;= B[SZ(B)-2]-B[SZ(B)-3]-1);
            if(p &lt;= n) { n -= p; continue; }
            //try 'b'
            p = 1;
            if(SZ(B)&gt;=2) p += 1;
            if(p &lt;= n) { n -= p; B.push_back(m); continue; }
            //try 'c' (assert n == 1)
            p = 1;
            if(p &lt;= n) { n -= p; continue; }
        }
        printf("%d\n", (int)m);
    }
    return 0;
}
</code></pre>

Reference solution (C++):
###C++  
```cpp  

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <queue>
#include <bitset>
#include <ctime>
#include <string>
#include <cstring>
#pragma comment(linker, "/STACK:256000000")
    
using namespace std;
    
const int maxN = 20000;
const int BOUND = 2000;
    
long long find_limit(long long k) {
 long long l = 0, r = 5000000;
 long long result = 0;
 while (l <= r) {
   long long key = (l + r) / 2;
   long long total = (key * (key + 1)) / 2;
   if (total <= k) {
     result = key;
     l = key + 1;
   } else {
     r = key - 1;
   }
 }
 return result;
}
    
char s[maxN];
    
void solvebig(long long k) {
 int MID = 10000;
 long long counta = find_limit(k);
 long long total = (counta * (counta + 1)) / 2;
    
 k -= total;
    
 if (k == 0) {
   cout << counta << endl;
   return;
 }
 if (k == 1) {
   cout << counta + 1 << endl;
   return;
 }
    
 MID = min(MID, (int)counta);
 for (int i = 0; i < MID; ++i) {
   s[i] = 'a';
 }
    
 int res = counta;
 s[MID] = 'b';
    
 --k;
    
 bool addonly_a = true;
 for (int i = MID + 1; ; ++i) {
   for (char c = 'a'; c <= 'z'; ++c) {
     s[i] = c;
     if (c != 'a') {
       addonly_a = false;
     }
     long long cur = 0;
     if (addonly_a) {
       cur = i - MID + 1;
     } else {
       int bound = min(MID, 2 * (i - MID + 10));
       bound = min(bound, i + 1);
       for (int j = 1; j <= bound; ++j) {
         bool good = true;
         for (int k = 0; k < j / 2; ++k) {
           if (s[i - k] != s[i - j + 1 + k]) {
             good = false;
             break;
           }
         }
         if (good) {
           ++cur;
         }
       }
     }
     if (cur == k) {
       cout << counta + (i - MID + 1) << endl;
       return;
     }
     if (cur < k) {
       k -= cur;
       break;
     }
   }
 }
}
    
int main() {
 //freopen("input.txt", "r", stdin);
 //freopen("output2.txt", "w", stdout);
    
 int t;
 cin >> t;
 for (int i = 0; i < t; ++i) {
   //cerr << i << endl;
   long long k;
   cin >> k;
   solvebig(k);
 }
    
 return 0;
}
```