ATcoder2038 【桁和 / Digit Sum】

  • 先考虑一些特殊情况比如 n > s n > s n>s n = s n=s n=s
  • n > s n > s n>s时,可以想象这样是无解的
  • n = s n = s n=s时, b = n + 1 b = n + 1 b=n+1
  • 然后呢,先考虑朴素做法:枚举 n n n以内所有数,作为 b b b
  • 当然 1 ≤ n ≤ 1 0 11 1\leq n \leq 10^{11} 1n1011,朴素做法肯定会TLE。
  • 当然看这个范围,如果以 O ( n ) O(\sqrt n) O(n )的算法肯定可过。
  • 我们就想想以 n \sqrt n n 为分界线
  • 小于 n \sqrt n n 就可以直接枚举 b b b的值
  • 而大于 n \sqrt n n 时又会怎么样呢
  • 可设整数 a , t a, t a,t使得 a ∗ b + t = n a * b + t = n ab+t=n a + t = s a+t=s a+t=s
  • 那么我们有 ( b − 1 ) ∗ a = n − s (b-1)*a=n-s (b1)a=ns
  • 那么答案就在 n − s n-s ns的质因数中了。
  • 枚举质因数,这道题就变成 O ( n ) O(\sqrt n) O(n )了。

code:

#include
#define ll long long 
using namespace std;

ll n, s, ans = -1;

inline ll read() {
	ll s = 0, f = 1;
	char ch;
	for(; ch < '0' || ch > '9'; ch = getchar())	if(ch == '-')	f = -1;
	for(; ch >= '0' && ch <= '9'; ch = getchar())	s = (s << 1) + (s << 3) + ch - '0';
	return s * f;
}

inline ll f(ll b, ll n) {
	ll ans = 0;
	while(n)	ans += n % b, n /= b;
	return ans;
}

int main() {
	n = read(), s = read();
	ll u = sqrt(n) + 1;
	for(ll i = 2; i <= u; ++i)	if(f(i, n) == s) { ans = i; break; }
	if(n == s) { ans = n + 1; }
	if(ans == -1 && n > s) {
		ll c = n - s;
		u = c / (u - 1) + 1;
		for(ll i = u; i >= 1; --i) {
			ll b = c / i + 1;
			if(!(c % i) && s >= i && (s - i) < b && i < b) {
				ans = b;
				break;
			}
		}
	}
	printf("%lld\n", ans);
	return 0;
}

又是一道结论题

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