本题要求n能被哪四个数的平方和组成,最暴力的做法是 枚举前三个数即 a b c,然后计算出最后一个数d 然后进行输出,在使用for进行枚举数字的时候,要让b=a,c=b,这样输出的时候一定是字典序
由于每个数的范围是小于等于根号n,因此若直接三重循环的话,会超时
做法
可以两个两个进行枚举,先枚举 c和d的值,将cc+dd的计算结果存放到一个数组sum里面,然后再枚举a 和b的值,计算t=n-aa-bb
在sum数组里面查找t值即可
如何保证字典序
在两两枚举的时候,需要让第二个数从第一个数的值开始枚举,这样可以保证两两之间字典序,要让 a b c d 形成字典序,需要我们将sum数组的值以及c和d的值进行排序,然后使用二分找到第一个等于t的值即可
如何在数组中找到t
在一个数组中寻找一个值,一般我们有两种方法.
1.二分查找,时间复杂度为logn
2.哈希表,时间复杂度为O(1)
代码如下
这里要注意java的排序
import java.util.*;
public class Main {
static List<Sum> list=new ArrayList<Sum>();
static int cnt=0;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
// 直接枚举前三个数 再求最后一个数 会超时 因此我们需要先枚举前两个数 再枚举后两个数
// 先枚举c 和d的组合 存放到数组里面 由于题目中要求按照字典序输出 因此我们需要对 c和d中的数值进行排序
for(int c=0;c*c<=n;c++) {
// d从c进行枚举 这样可以保证c和d是字典序
for(int d=c;c*c+d*d<=n;d++) {
// 记录c和d的平方和 以及c d的值
int t=c*c+d*d;
//记录下来
list.add(new Sum(c,d,t));
}
}
// 当计算完c 和d的组合之后 我们可以枚举a和b的值 计算a*a+b*b 然后在sum数组中寻找值等于 n-a*a+b*b的值
// 使用二分在sum数组里面进行查找 由于二分需要单调性 而且需要符合字典序 因此我们需要进行排序
// s值相同的情况下 要根据c和d的值进行排序选择
Comparator<Sum> cmp=new Comparator<Sum>() {
@Override
public int compare(Sum o1, Sum o2) {
// TODO Auto-generated method stub
if(o1.s!=o2.s) {
return o1.s-o2.s;
}else if(o1.c!=o2.c) {
return o1.c-o2.c;
}else {
return o1.d-o2.d;
}
}
};
list.sort(cmp);
for(int a=0;a<=n;a++) {
for(int b=a;a*a+b*b<=n;b++) {
int t=n-a*a-b*b;
int l=-1;
int r=list.size()-1;
// 需要找到第一次出现的位置
while(l+1<r) {
int mid=(l+r)/2;
if(list.get(mid).s<t) {
l=mid;
}else {
r=mid;
}
}
// 取右边
if(list.get(r).s==t) {
System.out.println(a+" "+b+" "+list.get(r).c+" "+list.get(r).d);
return;
}
}
}
}
}
class Sum{
public int c;
public int d;
public int s;
public Sum(int c,int d,int s) {
this.c=c;
this.d=d;
this.s=s;
}
}