等式的根-XJOIp1241
题目描述:有这样一个式子 x2+S(x)∗x−n=0 x,n都是正整数, S(x)为x所有十进制数位的和 ,现在给你一个n,你需要找到最小的x使得等式成立。
输入格式:输入一个整数 输出格式:输出一个整数 ,如果不存在一个整数使得等式成立,输出-1
样例输入1:110 样例输出1:10
样例输入2:4 样例输出2:-1
约定:1<=n<=10^18
思路:
题目的意思是找到满足等式的最小值,找不到就返回-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型进行比较。所以第一次提交只有28分,这是通过WA才得到的教训,切记,切记。
——————————————————————————————————————————————————————————————
AC的代码:
#include<bits/stdc++.h>
using namespace std;
long long n,x;
long long ans;
long long s,f;
int main(){
cin>>n;
for(long long i=max((long long)1,(long long)sqrt(n)-81);i<=sqrt(n);i++ ){ //int不能和long long比较,也得转换成long long。
x=i;
s=0;
while(x!=0){
s=s+x%10;
x/=10;
}
ans=i*i+s*i-n;
if(ans==0){
f=1;
cout<<i;
break;
}
}
if(f==0){
cout<<"-1";
}
}
————————————————
版权声明:本文为CSDN博主「birdstorm」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/birdstorm_s/article/details/20386413
浙公网安备 33010602011771号