2023/12/1第一次发帖纪念
· 题干
题目描述:火车从始发站(称为第 1 站)开出,在始发站上车的人数为 a,然后到达第 2 站,在第 2 站有人上、下车,但上、下车的人数相同,因此在第 2 站开出时(即在到达第 3 站之前)车上的人数保持为 a 人。从第 3 站起(包括第 3 站)上、下车的人数有一定规律:上车的人数都是前两站上车人数之和,而下车人数等于上一站上车人数,一直到终点站的前一站(第 n−1 站),都满足此规律。现给出的条件是:共有 n 个车站,始发站上车的人数为 a,最后一站下车的人数是 m(全部下车)。试问 x 站开出时车上的人数是多少?
输入格式:输入只有一行四个整数,分别表示始发站上车人数 a,车站数 n,终点站下车人数 m 和所求的站点编号 x。
输出格式:输出一行一个整数表示答案:从 x 站开出时车上的人数。
说明与提示:
对于全部的测试点,保证 1 ≤ a ≤ 20,1 ≤ x ≤ n ≤ 20,1 ≤ m ≤ 2×10^4
· 解题
首先根据题意是一个斐波那契数列的问题,我们先在纸上分析一波
对于每一个站,火车共有三个参数,分别是上车的人数, 下车的人数,和车上现有的人数
然后我们根据题目给的递推信息,发现关键的地方在于第二站上车和下车的人数是未知的,而一旦确定了,整道题也就迎刃而解了
定义第一站上车为a,第二站上下车人数为b。倘若这道题放到小学三年级,根据题设给的等量关系,我们肯定会列个方程然后把b解出来,现在我们的思路也是如此
参数\站数 | 1 | 2 | 3 | 4 | 5 | 6 | …… |
上车 | a | b | a+b | a+2b | 2a+3b | 3a+5b | …… |
下车 | 0 | b | b | a+b | a+2b | 2a+3b | …… |
在车上 | a | a | 2a | 2a+b | 3a+2b | 4a+4b | …… |
可见对于每一个车站的所有参数都是有公式的
将样例代入
4 * 5 + 4 * b = 32 b = 3 当 x = 4 代入得 人数为2 * 5 + 3 * 1 = 13 没问题
但是问题来了,怎么解方程呢?好像不能够“设”一个未知数哇!因为设一个没有实际数值(自动初始化为0)的未知数,后续任何乘法操作都是没有意义的
那就用他的系数表示,最后解方程的步骤也用系数来表示
我们不妨将表格稍加修改
参数\站数 | 1 | 2 | 3 | 4 | 5 | 6 | …… |
上车 | 1a+0b | 0a+1b | 1a+1b | a+2b | 2a+3b | 3a+5b | …… |
下车 | 0a+0b | 0a+1b | 0a+1b | a+b | a+2b | 2a+3b | …… |
在车上 | 1a+0b | 1a+0b | 2a+0b | 2a+b | 3a+2b | 4a+4b | …… |
我们便想到用两个数组来分别表示参数
但是这里为了便于理解我们用结构体数组来表示
注意:这个结构体数组表示的是表格的第一行,可能会好奇为什么不再建立一个用来表示第二行呢,其实不是不行,但是我们通过题目的机制与观察发现,第一行和第二行其实差不多(只有首末元素的差别,所以只需要建立一个就够了)
struct train {
int w_a, w_b;
} stat[25];
其中 w_a表示weight_a表示a的系数, w_b表示weight_b表示b的系数
剩下的和求斐波那契数列的方法一致,给出基
stat[1].w_a = 1;
stat[1].w_b = 0;
stat[2].w_a = 0;
stat[2].w_b = 1;
后面的项用循环就可求出
for(int i = 3; i < n; i++) {
stat[i].w_a = stat[i-1].w_a + stat[i-2].w_a;
stat[i].w_b = stat[i-1].w_b + stat[i-2].w_b;
}
要求第n站开车后车上的人数,其实就是前n-1站上车人数之和减去下车人数之和
接下来我们观察表格
由于“而下车人数等于上一站上车人数”这一条规律,图中红色和蓝色部分完全抵消了
所以我们要求的人数 = 第 n-1 站上车人数 + a - b(我们借助n >= 3的数据也能看出这个规律)
所以对于末站,末站n下车的人数其实就是n-1站开出的人数,我们便得到了这样的一个方程
a * stat [ n - 1 ] w_a + b * stat [ n-1 ] w_b + a - b = m (题中给的末站下车的人数)
从而将b求解出来
b = (m - a * (stat[n-1].w_a + 1)) / (stat[n-1].w_b - 1);
最后呢只需要代入所需的x,用上面的规律再处理即可得出答案
int people_x;
people_x = a * (stat[x].w_a + 1) + b * (stat[x].w_b - 1);
· 完整的代码
#include<stdio.h>
#define max 25
//建立结构体数组,内含a, b的参数
struct train {
int w_a, w_b;
} stat[25];
int main() {
//交互输入
int a, b, n, m, x;
scanf("%d%d%d%d", &a, &n, &m, &x);
//对数组前面两位赋值,便于接下来的计算
stat[1].w_a = 1;
stat[1].w_b = 0;
stat[2].w_a = 0;
stat[2].w_b = 1;
//利用斐波那契数列的递推公式计算各项
for(int i = 3; i < n; i++) {
stat[i].w_a = stat[i-1].w_a + stat[i-2].w_a;
stat[i].w_b = stat[i-1].w_b + stat[i-2].w_b;
}
//解出b
b = (m - a * (stat[n-1].w_a + 1)) / (stat[n-1].w_b - 1);
//代入公式
int people_x;
people_x = a * (stat[x].w_a + 1) + b * (stat[x].w_b - 1);
//交互输出
printf("%d", people_x);
return 0;
}
· 注:
第一次写题解,仅分享自己的思路,欢迎指出不足