【问题描述】
给定一个数 x,求正整数 y≥2,使得满足以下条件:
1.y-x 的绝对值最小;
2.y 的质因数分解式中每个质因数均恰好出现 2 次。
【输入数据】
第一行输入一个整数 T(1≤T≤50)
每组数据有一行,一个整数 x(1≤x≤10^18)
【输出数据】
对于每组数据,输出一行 y-x 的最小绝对值。
【输入样例 1】
5
1112
4290
8716
9957
9095
【输出样例 1】
23
65
67
244
70
【数据范围】
对于 20% 的数据, T = 1, x ⩽ 10^4
对于 50% 的数据, T ⩽ 10, x ⩽ 10^12
对于 70% 的数据, T ⩽ 30, x ⩽ 10^15
对于 100% 的数据, T ⩽ 50, x ⩽ 10^18
———————————————分割の线——————————————————————
【分析】
给定x求y,并且y给定了一定的条件。利用此条件求出使|x-y|最小的y值.
让我们分析一下这两个(半)条件:
取y使|x-y|的值最小是显而易见的。
y中分解的每个质因数只出现两次:
此处可以推得:y是一个完全平方数,开平方后仅由质数组成,且每个质数只出现一次(开方后不含平方数因子)。
代码实现时,可以先枚举i,使得i*i==y。这时需要检验,i是否含有平方数因子。可以定义变量j,从2枚举到sqrt(i)判断是否存在j*j是i的因数。
code
bool check(long long i)
{
long long large=(long long)sqrt(i),j=2;
while(j<=large)
{
if(i%(j*j)==0) return 0;
j++;
}
return 1;
}
剩下的半个条件是y>=2其实就是特判,
if(x<=4)
{
printf("%d\n",4-x);
continue;
}
完整代码如下:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long T,x;
bool check(long long x)
{
long long large=(long long)sqrt(x),i=2;
while(i<=large)
{
if(x%(i*i)==0) return 0;
i++;
}
return 1;
}//判断是否存在完全平方因子
int main()
{
freopen("abs.in","r",stdin);
freopen("abs.out","w",stdout);
cin>>T;
for(int i=1;i<=T;i++)
{
scanf("%lld",&x);
if(x<=4)
{
printf("%lld\n",4-x);
continue;
}//特判
long long a=(long long)sqrt(x),j1,j2,ans;
j1=a,j2=a+1;//分头枚举y的平方根
while(j1>=2)
{
if(check(j1))break;
else j1--;
}//枚举y的下限
while(j2<=x)
{
if(check(j2))break;
else j2++;
}//枚举y的上限
ans=min(abs(j2*j2-x),abs(j1*j1-x));//比较哪个y可以使|x-y|最小
printf("%lld\n",ans);
}
return 0;
}
写的不好,如有纰漏,请在下方评论区指出。