[HDU4143] A Simple Problem
题目
解说
显然数学题。
因为\(y^2=n+x^2\),所以移一下项可以得到\(y^2-x^2=n\),即\((y+x)(y-x)=n\),这样就很显然了,我们把\(n\)分解为\(a,b\),只要满足\(a=y+x,b=y-x\),即\(a+b=2y,a-b=2x\),即\(a-b\)是偶数即可,\(x\)就等于\((a-b)/2\)。
如果我们直接从\(1\)开始分解质因数的话,显然时间效率是\(O(\sqrt n)\),这个效率似乎不能再优化了,但是用一个小技巧可以让它稍微快一些。我们要找的是最小的\(x\),即我们想让\(a,b\)最接近,那么我们就不应该改从\(1\)开始循环,而应该从\(\sqrt n\)开始,这样我们找到的第一组符合条件的\(a,b\)就一定是差最小的,这时候直接\(break\)就行了,没必要再继续下面的循环了。
另外注意一点,题目中说了\(positive \ integer \ x\),即\(x\)是个正数,那么\(n\)是完全平方数的话输出\(0\)就错了(这个点卡了我一节课)。
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;bool flag=0;
scanf("%d",&n);
for(int i=sqrt(n);i>=1;i--){
if(n%i==0){
int b=n/i;
if(b==i) continue;
if((b-i)%2==0){
printf("%d\n",(b-i)/2);
flag=1;
break;
}
}
}
if(!flag) printf("-1\n");
}
return 0;
}
尾声:关于gyz大佬代码冗余部分的评论
最开始确实没发现\(x\)是正数这么回事,于是找来了\(gyz\)大佬的代码对拍,才发现了这个错,但是反观他的代码有许多冗余部分,很不优美,也不简洁,极大地影响了阅读体验,下面进行简短评论。
#include<cstdio>
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,res=-1;
scanf("%d",&n);
for(int i=1;i*i<n;i++){//没有从根号n开始影响时间,但这是思路的问题,无可厚非
if(n%i)continue;
int a=n/i;
if((a+i)%2||(a-i)%2||a-i<0)continue;//首先(a+i)%2,(a-i)%2只判一个就行,因为a-i是偶数a+i一定是偶数
//(a-i)<0用不着判断,a一定是大于i的,毕竟i是小于根号n的
if(res==-1||res>(a-i>>1))res=a-i>>1;//这里不用判断,毕竟以1到根号n的顺序找的话x一定是越来越小的
}
printf("%d\n",res);
}
return 0;
}
(以上仅是个人意见,无意侵犯)
幸甚至哉,歌以咏志。
签名:
我将轻轻叹息,叙述这一切,
许多许多年以后:
林子里有两条路,我——
选择了行人稀少的那一条,
它改变了我的一生。