[蓝桥杯 2019 省 B] 等差数列 |数学、最大公约数gcd、等差数列

题目链接:

P8682 [蓝桥杯 2019 省 B] 等差数列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 1.等差数列 - 蓝桥云课 (lanqiao.cn)

说明:

思路:

这道题首先想到的是先排序,因为等差数列是有一个大小顺序的。在这里按升序排,把数列看成非递减的,然后找出最小的差值,因为对于相差最小的这两个数,如果再把差值定大一点,这两个数就不能构成等差数列,再定小一点,要使这两个数构成等差数列就需要在中间插入数,就变长了,所以要尽在保持能够组成等差数列的同时可能少插入,所以以这两个数的差值做等差数列的差值,其他的两个数之间插入数来构成等差数列。

这样想好像没问题,但是:

如果最小差值为2d,某两项ai,ai+1差值为3d,那么就无法插入一个整数使得ai、插入的数、ai+1变成等差数列

于是就要找差值的最大公约数,因为只有公差为每个差值的约数才能在两个数之间插入自然数(从0开始的整数) 个 数字,使得序列变成等差数列。结合之前的要找大一点的数做公差,减少插入的数,使数列最短,那么就是找最大公约数了。

再用另一种说法来说明:对于等差数列有公式(an-a1) / d =n-1,d为公差。
因为要最短,不可能再添加比an更大的数或者比a1更小的数,那会使数列更长。所以(an-a1) 就确定了,于是当d越大,项数n越小。所以要保证序列为等差数列的同时,保证公差d最大。

因为该序列是等差数列的子序列。所以相邻两项的差一定是公差的倍数,即公差是所有相邻两项差的公约(因)数。我们的目标是公差d最大,那就求出序列所有相邻两项差的最大公因数, 最大公因数就是最大公差。

注意点:

1.1.C++库自带求最大公约数的函数,__gcd(a,b)。

2.公差为0的情况的特判

代码:

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=1e5+10;
//先排序,按升序排,因为等差数列一定是非递减的,然后找出最小的差值,因为 
//对于相差最小的这两个数,如果再把差值定大一点,这两个数就不能构成等差数列,
//再定小一点,要使这两个数构成等差数列就需要在中间插入数,就变长了,
//所以要尽在保持能够组成等差数列的同时可能少插入,所以以这两个数的差值做等差数列的差值,其他的两个数之间插入数
// 找差值的最大公约数
int n;
int ans=0;
int a[N];
signed main(){
	
  //关同步!!!
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0); 
	cin>>n;
	
	for(int i=0;i<n;i++){
	    cin>>a[i];
	}
	
	sort(a,a+n);
	
	int diff=__gcd(a[1]-a[0],a[2]-a[1]);
	for(int i=3;i<n;i++){
	    diff=__gcd(a[i]-a[i-1],diff);
	}
	
	 //等差数列 差值为0的情况
	if(diff==0) ans=n;
	else
	ans=(a[n-1]-a[0])/diff +1;
	
	cout<<ans;
	return 0;
} 

### 十届蓝桥杯 等差数列 题目解析 #### 题目描述 数学老师给小明出了一道等差数列求和的题目。然而,粗心的小明忘记了完整的数列,仅记住了其中 \( N \) 个整数。现在给出这 \( N \) 个整数,小明希望知道包含这些整数的最短的等差数列有多少项。 输入数据为一组整数列表,目标是找到能够覆盖所有这些整数的最小长度的等差数列[^2]。 --- #### 解题思路 为了构建满足条件的最短等差数列,可以按照如下逻辑实现: 1. **排序并计算可能的公差** 将输入的整数按升序排列,并通过相邻两项之差来获取候选公差集合。如果存在重复数值,则直接返回当前序列长度作为结果[^3]。 2. **确定最终公差** 对于上述得到的所有可能的公差值,取它们的最大公约数 (GCD),以此作为整个等差数列的实际公差。 3. **计算总项数** 使用首尾两端的距离除以选定的公差再加一即可得出所需最少项的数量公式:\((a_{max} - a_{min}) / d + 1\) ,这里 \(d\) 表示所选公差[^1]。 以下是基于此方法的具体 Python 实现代码: ```python from math import gcd from functools import reduce def find_min_arithmetic_sequence_length(nums): nums.sort() # 如果只有一个元素或者全是相同元素, 返回其数量 if len(set(nums)) == 1: return len(nums) diffs = [] for i in range(1, len(nums)): diffs.append(abs(nums[i]-nums[i-1])) # 计算最大公约数(GCD) common_diff = reduce(gcd, diffs) min_num = nums[0] max_num = nums[-1] # 序列长度计算 sequence_length = ((max_num - min_num)//common_diff)+1 return sequence_length # 测试例子 test_case = [2, 6, 4, 10, 20] print(find_min_arithmetic_sequence_length(test_case)) ``` 该函数首先对输入数组进行去重与排序操作,接着找出每一对连续数字间的绝对差异构成的新列表 `diffs` 。随后利用内置库中的功能快速定位到这些差距间最大的共同因子——也就是我们所需要的公共差别量度 `common_diff` 。最后依据已知边界点以及这个通用间隔推导出完整系列应有的成员数目。 --- #### 结果验证 对于样例 `[2, 6, 4, 10, 20]`, 排序后的版本将是 `[2, 4, 6, 10, 20]`. 这些值之间依次产生的距离分别是 `[2, 2, 4, 10]` , 它们的 GCD 是 2 . 所以形成的最简形式应该是从 2 开始每隔两个单位增加一次直到达到或超过终点位置 20 止 —— 即序列 {2, 4, 6,..., 20}, 总共有十个项目. ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CGuts350

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值