东华OJ基础 54 等差数列
问题描述
一个等差数列是一个能表示成a, a+b, a+2b,…, a+nb (n=0,1,2,3,…) 在这个问题中a是一个非负的整数,b是正整数。
写一个程序来找出在双平方数集合S中长度为n的等差数列。双平方数集合是所有能表示成p2+q2的数的集合。
输入说明
第一行: N(3<= N<=25),要找的等差数列的长度。 第二行: M(1<= M<=250),搜索双平方数的上界0 <= p,q <= M。
输出说明
如果没有找到数列,输出`NONE’。
如果找到了,输出一行或多行, 每行由两个整数组成:a,b 这些行应该先按b排序再按a排序(均为升序)。
将不会有多于10,000个等差数列。
解答
#include<iostream>
#include<algorithm>
const int maxs=250*250+10;
using namespace std;
struct ans{
int a;
int b;
};
int comparation(ans x1, ans x2){
if(x1.b == x2.b) {
return x1.a < x2.a;
}
return x1.b < x2.b;
}
int main(){
int N;
int M;
scanf("%d %d", &N, &M);
int vis[250 * 250 + 10] = {0};
int vi[250 * 250 + 10] = {0};
ans as[250 * 250 + 10];
int length = 0;
for(int i = 0; i <= M; i++) {
for(int j = i; j <= M; j++) {
if(vis[i * i + j * j] == 0) {
vi[length++] = i * i + j * j;
vis[i * i + j * j] = 1;
}
}
}
sort(vi, vi + length);
int index = 0;
for(int i = 0; i < length; i++) {
for(int j = i + 1; j < length; j++) {
if(vi[i] + (N - 1) * (vi[j] - vi[i]) > vi[length - 1]) {
continue;
}
int d = vi[j] - vi[i];
int a = vi[j];
int k = 2;
while(vis[a + d] != 0 && a + d <= vi[length - 1] && k < N) {
k++;
a = a + d;
}
if(k == N) {
as[index].a = vi[i];
as[index].b = d;
index++;
}
}
}
if(index == 0) {
printf("NONE");
}
sort(as,as + index, comparation);
for(int i = 0; i < index; i++) {
printf("%d %d\n",as[i].a,as[i].b);
}
return 0;
}
下面内容来自Chat-GPT 4o
这段代码的目的是在给定的范围内寻找长度为 N
的等差数列,且数列中的元素属于双平方数集合。程序从输入获取要搜索的等差数列长度 N
和搜索的上界 M
,然后寻找符合条件的等差数列并输出。若没有找到任何等差数列,则输出 “NONE”。
头文件和常量定义
#include<iostream>
#include<algorithm>
const int maxs = 250 * 250 + 10;
#include<iostream>
:包含输入输出流库,方便进行输入输出操作。#include<algorithm>
:包含常用算法库,如排序函数。const int maxs = 250 * 250 + 10;
:定义常量maxs
,表示双平方数的最大值为250² + 250² = 125000
,再加上一个额外的 10,以便于使用数组来存储相关的值。
结构体定义
struct ans{
int a;
int b;
};
定义一个结构体 ans
,包含两个整数成员 a
和 b
。这两个成员分别用于存储等差数列的首项 a
和公差 b
。
排序比较函数
int comparation(ans x1, ans x2){
if(x1.b == x2.b) {
return x1.a < x2.a;
}
return x1.b < x2.b;
}
定义了一个比较函数 comparation
,用于在排序时比较两个 ans
结构体:
- 如果
b
相等,则按照a
升序排列。 - 否则,按照
b
升序排列。
主函数部分
int main(){
int N;
int M;
scanf("%d %d", &N, &M);
- 读取输入的两个整数
N
和M
,分别表示等差数列的长度和双平方数的搜索上界。
int vis[250 * 250 + 10] = {0};
int vi[250 * 250 + 10] = {0};
ans as[250 * 250 + 10];
int length = 0;
vis
数组用于标记是否已访问某个双平方数。vi
数组用于存储所有计算出来的双平方数。as
数组用于存储符合条件的等差数列的首项a
和公差b
。length
变量用于记录vi
数组中双平方数的个数。
生成双平方数
for(int i = 0; i <= M; i++) {
for(int j = i; j <= M; j++) {
if(vis[i * i + j * j] == 0) {
vi[length++] = i * i + j * j;
vis[i * i + j * j] = 1;
}
}
}
通过嵌套循环生成所有 p² + q²
形式的双平方数(其中 p
和 q
从 0
到 M
)。当找到一个新的双平方数时,将其存入 vi
数组,并更新 vis
数组,标记该数已被访问。
排序双平方数
sort(vi, vi + length);
将 vi
数组中的双平方数按升序排序。
寻找等差数列
int index = 0;
for(int i = 0; i < length; i++) {
for(int j = i + 1; j < length; j++) {
if(vi[i] + (N - 1) * (vi[j] - vi[i]) > vi[length - 1]) {
continue;
}
int d = vi[j] - vi[i];
int a = vi[j];
int k = 2;
while(vis[a + d] != 0 && a + d <= vi[length - 1] && k < N) {
k++;
a = a + d;
}
if(k == N) {
as[index].a = vi[i];
as[index].b = d;
index++;
}
}
}
- 外层循环
i
和内层循环j
用于遍历vi
数组中的每一对数。 - 对于每一对数
vi[i]
和vi[j]
,计算它们的公差d = vi[j] - vi[i]
。 - 判断从
vi[i]
开始,步长为d
的数列是否可以构造出长度为N
的等差数列。- 如果无法构造出,跳过当前的
i, j
。 - 如果能构造出,检查每一项是否在双平方数集合中,并且小于或等于最大双平方数。
- 如果无法构造出,跳过当前的
- 如果成功找到长度为
N
的等差数列,就将首项vi[i]
和公差d
存入as[index]
。
判断是否找到等差数列
if(index == 0) {
printf("NONE");
}
如果 index
为 0,表示没有找到符合条件的等差数列,输出 “NONE”。
输出结果
sort(as, as + index, comparation);
for(int i = 0; i < index; i++) {
printf("%d %d\n", as[i].a, as[i].b);
}
- 使用
sort
函数按照comparation
函数对as
数组中的等差数列进行排序。 - 输出所有找到的等差数列的首项和公差。
程序结束
return 0;
}
程序结束,返回 0,表示程序成功执行完毕。
总结:
这段代码的目标是通过生成双平方数集合,检查其中是否存在满足特定条件的等差数列。最终输出所有符合条件的等差数列的首项和公差,如果没有找到则输出 “NONE”。