洛谷P1011 车站 [NOIP1998 提高组] 题解(C语言)

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解出来,现在我们的思路也是如此

参数\站数123456……
上车aba+ba+2b2a+3b3a+5b……
下车0bba+ba+2b2a+3b……
在车上aa2a2a+b3a+2b4a+4b……

可见对于每一个车站的所有参数都是有公式

将样例代入

4 * 5 + 4 * b = 32   b = 3  当 x = 4 代入得   人数为2 * 5 + 3 * 1 = 13 没问题

但是问题来了,怎么解方程呢?好像不能够“设”一个未知数哇!因为设一个没有实际数值(自动初始化为0)的未知数,后续任何乘法操作都是没有意义的

那就用他的系数表示,最后解方程的步骤也用系数来表示

我们不妨将表格稍加修改

参数\站数123456……
上车1a+0b0a+1b1a+1ba+2b2a+3b3a+5b……
下车0a+0b0a+1b0a+1ba+ba+2b2a+3b……
在车上1a+0b1a+0b2a+0b2a+b3a+2b4a+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;
}

· 注:

第一次写题解,仅分享自己的思路,欢迎指出不足

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值