Problem:
Score : 500 points

Problem Statement

For integers b (b \geq 2) and n (n \geq 1), let the function f(b,n) be defined as follows:

f(b,n) = n, when n < b

f(b,n) = f(b,\,{\rm floor}(n / b)) + (n \ {\rm mod} \ b), when n \geq b

Here, {\rm floor}(n / b) denotes the largest integer not exceeding n / b,
and n \ {\rm mod} \ b denotes the remainder of n divided by b.

Less formally, f(b,n) is equal to the sum of the digits of n written in base b.
For example, the following hold:

f(10,\,87654)=8+7+6+5+4=30

f(100,\,87654)=8+76+54=138

You are given integers n and s.
Determine if there exists an integer b (b \geq 2) such that f(b,n)=s.
If the answer is positive, also find the smallest such b.

Constraints

1 \leq n \leq 10^{11}

1 \leq s \leq 10^{11}

n,\,s are integers.

Input

The input is given from Standard Input in the following format:

n
s

Output

If there exists an integer b (b \geq 2) such that f(b,n)=s, print the smallest such b.
If such b does not exist, print -1 instead.

Sample Input 1

87654
30

Sample Output 1

10

Sample Input 2

87654
138

Sample Output 2

100

Sample Input 3

87654
45678

Sample Output 3

-1

Sample Input 4

31415926535
1

Sample Output 4

31415926535

Sample Input 5

1
31415926535

Sample Output 5

-1

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
using System.Text;//テキストの高速出力に必要
class Program
{
	static void Main()
	{
		long n = long.Parse(Console.ReadLine());
    long s = long.Parse(Console.ReadLine());
		long answer = -1;
    long[] divisions = DivisionCompression(n);
    int divisionsCount = divisions.Length;
    long answerBack = 1;
    long answerNow = 0;

    for(int i = 0; i < divisionsCount; i++)
    {
      answerNow += divisions[i];
      if(i == 0) continue;

      if(divisions[i] == 1)
      {
        if(findSumOfDigits(n,answerNow) == s)
        {
          answer = answerNow;
          break;
        }
      }else
      {
        long div = n/answerNow;
        long rest = n%answerNow;
        long inter = (n%(answerBack+1)) - (n%answerNow);
        long interCount = answerNow-(answerBack+1);
        inter /= interCount;
        if((s-div) % inter == rest)
        {
          long divMemo = (s-div)/inter;
          //Console.WriteLine(answerBack+" "+answerNow+" "+divMemo+" "+(answerNow-divMemo));
          if(answerNow-divMemo > answerBack && n/(answerNow-divMemo)+n%(answerNow-divMemo)==s)
          {
            answer = answerNow-divMemo;
            //Console.WriteLine(answerBack+" "+answerNow+" "+divMemo);
            break;
          }
        }
      }

      answerBack = answerNow;
    }
    
    if(answer == -1)
    {
      if(n == s) answer = n+1;
    }

		Console.WriteLine(answer);
	}

  static long findSumOfDigits(long n, long x) 
  {//引数をnとして、nのx進数で各桁の数の和を求める
    long sum = 0;
    while (n > 0) 
    { // n が 0 になるまで
      sum += n % x;
      n /= x;
    }
    return sum;
  }

  static long[] DivisionCompression(long num)
  {//x=1~numまでを[n/x]の値で座標圧縮。配列の個数を2√numまで圧縮できる。
  //返り値の配列は圧縮前の個数。
  //例えばnum=10なら、[1,1,1,2,5]を返す。
    long dividesCount = (long)Math.Sqrt(num);
    long[] divides = new long[(int)dividesCount+1];//前半の(x/i)の値
    long[] answers;
    for(long i = 0; i < (int)dividesCount; i++)
    {
      divides[(int)i] = num/(i+1);
    }

    if(divides[(int)dividesCount-1] == dividesCount)
    {
      answers = new long[2*(int)dividesCount-1];
      for(int i = 0; i < (int)dividesCount; i++) answers[i] = 1;

      for(int i = 0; i < (int)dividesCount-1; i++)
      {
        answers[(int)dividesCount+i] = divides[(int)dividesCount-2-i]-divides[(int)dividesCount-1-i];
      }
    }else
    {
      answers = new long[2*(int)dividesCount];
      for(int i = 0; i < (int)dividesCount; i++) answers[i] = 1;

      divides[(int)dividesCount] = dividesCount;
      for(long i = 0; i < dividesCount; i++)
      {
        answers[(int)dividesCount+i] = divides[(int)dividesCount-1-i]-divides[(int)dividesCount-i];
      }
    }
    
    return answers;
  }
  
}