ARC-060D - Digit Sum - 数论

题解链接

https://www.lucien.ink/archives/230/


题目链接

https://arc060.contest.atcoder.jp/tasks/arc060_b


题目

Problem Statement

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(nb))+(n mod b) f ( b , n ) = f ( b ,   f l o o r ( n ⁄ b ) ) + ( n   m o d   b ) , when nb n ≥ b
Here, floor(nb) f l o o r ( n ⁄ b ) denotes the largest integer not exceeding nb 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(b2) 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 .

Constraints

1n1011 1 ≤ n ≤ 10 11
1s1011 1 ≤ s ≤ 10 11
n n , s s are integers.

Input

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

n
s

Output

If there exists an integer b(b2) 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 (2b) 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 为最低位),那么有:

x0+x1·b+x2·b2+xm·bm=n x 0 + x 1 · b + x 2 · b 2 + … x m · b m = n
x0+x1+x2++xm=s x 0 + x 1 + x 2 + ⋯ + x m = s

  考虑某个进制 b b ,使得n b b 进制下的表示的最高次幂大于等于 2 2 次幂,则有: b2n=bn b 2 ≤ n = b ≤ n ,于是我们在 b b 进制的最高次为2次幂及以上的时候直接暴力枚举即可。

  对于最高次为一次幂的 b b ,等式为:

x0+x1·b=n   x 0 + x 1 · b = n     ①
x0+x1=s   x 0 + x 1 = s     ②

  将 式移项并代入 式得:

sx1+x1·b=n s − x 1 + x 1 · b = n
x1·(b1)=ns x 1 · ( b − 1 ) = n − s

  于是我们可以从大到小枚举 x1 x 1 (相当于从小到大枚举 (b1) ( b − 1 ) ),判断一下是否存在合法 b b 的即可。

  因为前面我们枚举 b b 的时候已经枚举过 [2,n] [ 2 , n ] 的范围,而 ns n − s 显然小于 n n ,所以我们第二次枚举只用枚举 (n,ns] ( 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");
}

你可能感兴趣的:(题解,数论,题解,arc,atcoder,数论)