https://www.lucien.ink/archives/230/
https://arc060.contest.atcoder.jp/tasks/arc060_b
For integers b(b≥2) and n(n≥1), let the function f(b,n) be defined as follows:
f(b,n)=n f ( b , n ) = n , when n<b n < b
f(b,n)=f(b,floor(n⁄b))+(n mod b) f ( b , n ) = f ( b , f l o o r ( n ⁄ b ) ) + ( n m o d b ) , when n≥b n ≥ b
Here, floor(n⁄b) f l o o r ( n ⁄ b ) denotes the largest integer not exceeding n⁄b n ⁄ b , and n mod b b denotes the remainder of n n divided by b b .
Less formally, f(b,n) f ( b , n ) is equal to the sum of the digits of n written in base b b . For example, the following hold:
f(10,87654)=8+7+6+5+4=30 f ( 10 , 87654 ) = 8 + 7 + 6 + 5 + 4 = 30
f(100,87654)=8+76+54=138 f ( 100 , 87654 ) = 8 + 76 + 54 = 138
You are given integers n n and s s . Determine if there exists an integer b(b≥2) b ( b ≥ 2 ) such that f(b,n)=s f ( b , n ) = s . If the answer is positive, also find the smallest such b b .
1≤n≤1011 1 ≤ n ≤ 10 11
1≤s≤1011 1 ≤ s ≤ 10 11
n n , s s are integers.
The input is given from Standard Input in the following format:
n
s
If there exists an integer b(b≥2) b ( b ≥ 2 ) such that f(b,n)=s f ( b , n ) = s , print the smallest such b b . If such b b does not exist, print −1 − 1 instead.
给你一个n
和一个s
,问是否存在一个 b (2≤b) b ( 2 ≤ b ) ,使得n
在 b b 进制下各位数字的和为s
,如果存在,则输出这个 b b ,如果不存在,则输出-1
。
假设 x0,x1,…,xm x 0 , x 1 , … , x m 为n
在 b b 进制下的各位数字( x0 x 0 为最低位),那么有:
考虑某个进制 b b ,使得n
在 b b 进制下的表示的最高次幂大于等于 2 2 次幂,则有: b2≤n=b≤n‾√ b 2 ≤ n = b ≤ n ,于是我们在 b b 进制的最高次为2次幂及以上的时候直接暴力枚举即可。
对于最高次为一次幂的 b b ,等式为:
将 ② ② 式移项并代入 ① ① 式得:
于是我们可以从大到小枚举 x1 x 1 (相当于从小到大枚举 (b−1) ( b − 1 ) ),判断一下是否存在合法 b b 的即可。
因为前面我们枚举 b b 的时候已经枚举过 [2,n‾√] [ 2 , n ] 的范围,而 n−s‾‾‾‾‾√ n − s 显然小于 n‾√ n ,所以我们第二次枚举只用枚举 (n‾√,n−s] ( n , n − s ] 这个区间就可以了。
#include
long long n, s;
bool check(long long base) {
long long ret = 0, tmp = n;
while (tmp) ret += tmp % base, tmp /= base;
return ret == s;
}
bool check(long long a1, long long tmp, long long a0 = 0, long long b = 0) {
return (a0 = s - a1) >= 0 && a0 < (b = tmp / a1 + 1) && a1 < b;
}
int main() {
scanf("%lld%lld", &n, &s);
long long up = (long long)sqrt(n) + 1;
for (long long base = 2; base <= up; base++) if (check(base)) return 0 * printf("%lld\n", base);
if (n <= s) return 0 * printf("%lld\n", n < s ? -1: n + 1);
long long tmp = n - s, upper = tmp / up + 1;
for (long long a1 = upper; a1 >= 1; a1--)
if (!(tmp % a1) && check(a1, tmp)) return 0 * printf("%lld\n", tmp / a1 + 1);
return 0 * puts("-1");
}