蓝桥杯原题——四平方和c++重载“>“,“<“逻辑运算符或用户自定义排序规则+sort()函数实现结构体多关键字排序

前言:

在结构体中重写大于小于号是一种很实用的技巧,重写">","<"后再使用c++自带的sort()排序可以解决大部分对输出有特殊要求的题目,当然也可以不进行重写,对sort()函数第三个参数(排序规则)进行编辑也可达到此目的,下面是原题和两种方式的写法:

题目:

四平方和定理,又称为拉格朗日定理:

每个正整数都可以表示为至多4个正整数的平方和。

如果把0包括进去,就正好可以表示为4个数的平方和。

比如:

5=02+02+12+22
7=12+12+12+22

对于一个给定的正整数,可能存在多种平方和的表示法。

要求你对4个数排序:

0≤a≤b≤c≤d

并对所有的可能表示法按 a,b,c,d为联合主键升序排列,最后输出第一个表示法。

(注意加粗部分的描述,对数据输出有特殊要求,意思就是按a < b < c < d的字典序输出)

输入格式

输入一个正整数 N。

输出格式

输出4个非负整数,按从小到大排序,中间用空格分开。

数据范围

0<N<5∗10^6

输入样例:
5
输出样例:
0 0 1 2

首先介绍重写“>”,"<"方法:

struct num{
    int a,b,c;
    bool operator <(const num &p) const{//重载“<”号 ,比较运算符需要两个数据进行比较,如x < y,在这里函数中的p是传入的参数,也就是后者y 
    	if(a != p.a){//第一关键字 
    		return a < p.a;//第一关键字不同则比较第一关键字 
		}
    	else if(b != p.b){//第二关键字 
    		return b < p.b;//第二关键字不同则比较第二关键字 
		}
    	else{
    		return c < p.c;//第三关键字 
		}
    	//可以继续添加第四第五等.... 
    }
};

num data[100];

sort(data, data + count);//后续输入数据后直接调用sort即可 

再来看自定义sort()排序函数方法:

struct num{
	int a, b, c;
};

num data[100];

bool check(num x,num y){//自定义排序规则函数,注意返回值类型必须是bool类型 
    if(x.a != y.a){
    	return x.a < y.a;
	} 
    else if(x.b != y.b){
    	return x.b < y.b;
	} 
    else{
    	return x.c < y.c;
	}
}

sort(data, data + count, check);//注意第三个参数传入排序函数

最后是题解:

这里用的二分查找的纯暴力做法+结构体排序,思路是先暴力枚举c和d的所有情况建立字典,再对a和b进行暴力,枚举时直接使用二分查找之前建立字典的方法(空间换时间)优化掉对c和d的暴力枚举,这里时间复杂度为O(n^2logn)可以通过所有测试集,这边只示范了自定义sort()排序方法的代码,重写">"或"<"的代码可以自行修改:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;

struct num{
	int sum, c, d;
};

bool check(num x, num y){
    if(x.sum != y.sum){
        return x.sum < y.sum;
    }
    else if(x.c != y.c){
        return x.c < y.c;
    }
    else{
        return x.d < y.d;
    }
}

const int N = 2500010;//根据组合类型枚举大致求出,枚举c与d并存入num进行排序时c至多有(√n * √n)/2种可能 
num record[N];
int n; 

int main(){
	scanf("%d", &n);
	int count = 0;
	for(int c = 0; c * c <= n; c++){
		for(int d = c ;c * c + d * d <= n; d++){
			record[count++] = {c * c + d * d, c, d};
		}
	}
	
	sort(record, record + count, check);
	
	for(int a = 0; a * a <= n; a++){ 
		for(int b = a; b * b + a * a <= n; b++){
			
			int target = n - b * b - a * a;
			
			int l = 0, r = count;
			while(l < r){
				int mid = (l + r) / 2;
				if(record[mid].sum < target){
					l = mid + 1;
				}
				else{
					r = mid;
				}
			}
			
			if(record[r].sum == target){
				printf("%d %d %d %d", a, b, record[r].c, record[r].d);
				return 0;
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值