题目描述
考虑等式:
x2 + s(x)·x - n = 0,
其中x,n是正整数,s(x)是个函数,其值等于x在十进制下所有数字的和。
现给出整数n的大小,请你求出最小的满足条件的正整数x。
输入格式
输入仅包含一个整数n (1 ≤ n ≤ 1018) .
输出格式
如果不存在这样的x,请输出-1;否则请输出满足条件的最小的整数x (x > 0)
输入样例
2
输出样例
1
下课回来就看到这么一道好题, 做了以后深受启发。
题目的大意是找到满足等式的最小值,找不到就返回-1。 看起来不难理解, 但是数据范围却是达到了10^18,用暴力必然TLE。
那么重点就是考虑怎么缩小搜索的范围。
首先我们看到 S(x) 代表x在十进制内各位数字之和,那么事实上 S(x) 的范围是确定的,其上界为所有位数均为9时,即S(x)≤18*9
其次,我们把等式进行转换,x+S(x)=n/x 这个整数方程似乎表明x是n的一个约数,但是求约数也是十分繁琐的过程。
这时我们注意到:n既然可以拆分为 x*(x+S(x)) ,那么x和x+S(x)分别在sqrt(n)的两侧。这是一个很简单的证明,这里也不提。
这个发现对于解决本题的大数据有很大的关键,因为S(x)必然大于0,则x必然小于x+S(x),也就是说x<sqrt(n) 和 x+S(x)>sqrt(n) 恒成立。
所以x的范围其实被压缩到了18*9以内。现在只要进行枚举就能很快的解出此题了。
事实上,我们还可以进一步压缩x的范围,x不会大于sqrt(n),所以不会超过10^9,S(x)的范围也被压缩到了9*9以内。
本题另一个难点就在于和long long有关的判断,int型不能直接和long long型进行比较。所以第一次提交十个测试点只通过四个,这是通过WA才得到的教训,切记,切记。
/*
USER_ID: test#birdstorm
PROBLEM: 130
SUBMISSION_TIME: 2014-03-03 17:23:58
*/
#include <stdio.h>
#include <math.h>
#define MIN(x,y) (x)<(y)?(x):(y)
#define INF 1000000007
long long s(long long x)
{
long long sum=0;
while(x){
sum+=x%10;
x/=10;
}
return sum;
}
main()
{
long long x, n, min=INF;
int i, k;
scanf("%lld",&n);
for(i=(int)(sqrt(n)+1),k=1; k<=9*9 && i>0; k++, i--)
if(((long long)(i)*(long long)(i)+(long long)(s(i)*i))==n) min=MIN(min,i);
printf("%lld\n",min==INF?-1:min);
return 0;
}