ARC060 D Digit Sum 数

版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/83278036

题目链接

题意:
给你一个n一个s,问你是否存在一个进制使得n在x进制下的各个位之和是s。n,s<=1e11。

题解:
乍一看确实没什么好办法,只会暴力枚举进制判断。

这题其实并没有用到什么更高明的判断方法,但是优化了枚举。

这里用到了一种经常会见到但是又很巧妙的思想:对于小于等于 n \sqrt{n} 的和大于 n \sqrt{n} 的进行分类讨论。

对于小于等于 n \sqrt{n} 的情况,我们只需要暴力判断即可。我们考虑该进制大于 n \sqrt{n} 的情况,应该有 a x + b = n , a + b = s a*x+b=n,a+b=s ,其中 x x 为进制。两式相减可以得到: a x = n s a*x=n-s ,由此可知, x x n s n-s 的因子,于是我们用 n s \sqrt{n-s} 的时间对 n s n-s 进行因数分解,对于每个因数进行暴力判断就可以了。如果没有解就输出-1。

代码:

#include <bits/stdc++.h>
using namespace std;

long long n,s;
inline long long f(long long b,long long n)
{
 if(n<b)
 return n;
 return f(b,n/b)+n%b;
}
int main()
{
 scanf("%lld%lld",&n,&s);
 if(s==n)
 {
  printf("%lld\n",n+1);
  return 0;
 }
 if(s>n)
 {
  printf("-1\n");
  return 0;
 }
 for(long long i=2;i<=sqrt(n)+1;++i)
 {
  if(f(i,n)==s)
  {
   printf("%lld\n",i);
   return 0;
  }
 }
 long long ji=n-s,ans=1e11;
 for(long long i=1;i*i<=ji;++i)
 {
  if(ji%i==0)
  {
   long long b=ji/i+1;
   if(f(b,n)==s)
   ans=min(ans,b);
  }
 }
 if(ans==1e11)
 printf("-1\n");
 else
 printf("%lld\n",ans);
 return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/83278036