2024-04-03-洛谷P1011 车站 做题思路及解析

 

前言

​ 上次写博客居然都快是两年前了啊,总觉得荒废了好多时间,不过这是我活该吧. 中间我考了一个中考.在高中加入了信息竞赛的培训班(虽然就四个人),不过在编程这块也算走上正轨了吧. 这是课上提到的一题,还挺有意思的,于是我就在周末花了一点时间写掉了这题. 那么下面正式开始

1.题目解析

题目链接:[P1011 [NOIP1998 提高组] 车站 - 洛谷 计算机科学教育新生态 (luogu.com.cn)](https://www.luogu.com.cn/problem/P1011)

火车从始发站(称为第 1 站)开出,在始发站上车的人数为a,然后到达第 2 站,在第 2 站有人上、下车,但上、下车的人数相同,因此在第 2 站开出时(即在到达第 3 站之前)车上的人数保持为 a 人。从第 3 站起(包括第 3 站)上、下车的人数有一定规律:上车的人数都是前两站上车人数之和,而下车人数等于上一站上车人数,一直到终点站的前一站(第 n−1 站),都满足此规律。现给出的条件是:共有 n 个车站,始发站上车的人数为 a,最后一站下车的人数是 m(全部下车)。试问 x 站开出时车上的人数是多少?

​ 总体来讲就是个普及难度,不是很难,不过再难我应该也做不来了,所以来看题目.

​ 此时我们读题,发现其实最主要的 难点 在于第二站的上车和下车的人数不知道,这样的题目题目对于我们来说就需要逆向去解决了.

不过对于这种一看有规律的题目,最好是画一个图

pFbFmN9.png 因为第二站上车下车的人数不知道,所以不妨设为t Δ:离站后车上的人的变化量

​ 那么此时观察规律(你们可以自己多写两组),不难得出Δ的值其实是一个斐波那契数列 ​ 不过此时仍然有一些难点要解决,由于t的值未知,那么对delta直接进行斐波那契的运算显然是不可行的,那么此时再次观察规律,得a与t的系数都是一个特殊的斐波那契

​ 其中a的系数的数列为: 0 1 0 1 1 2 3 … ​ t的系数的数列为: 0 0 1 1 2 3 5 …

​ 后面就主要注意Δ值的下标和站数的关系就可以了

​ 至此题目的所有难点都解析完了,接下来看用递归实现的代码解析

2.代码解析

(1) 递归实现斐波那契数列

​ 首先是a的系数的斐波那契 ​ 此时封装成一个函数,便于后续的使用

int fib_a(int n)
{
    if (n == 1)
        return 1;//特判

    if (n == 2)
        return 0;//特判
        
    return fib_a(n - 1) + fib_a(n - 2);//斐波那契递归
}

​ 虽然数列是 0 1 0 …但是斐波那契是从第2,3个数开始的,所以出于便于理解,这里将第2,3个数作为数列的第一个数字开始

​ x的系数同理,只不过注意这里第一个数是0,第二个数是1

int fib_x(int x)
{
    if (x == 1)
        return 0;//特判

    if (x == 2)
        return 1;//特判
        
    return fib_x(x - 1) + fib_x(x - 2);//斐波那契递归
}

(2)计算每站未知数系数的函数实现

​ 在实现斐波那契后,我们得到的只是每站的delta中未知数的系数.

​ 而最终与m相关联的出站后人数是之前所有delta和初始值的累加,所以为了方便处理,封装一个函数实现

​ 先看a的系数

int p_a(int n)//输入第几站
{
    int ans = 1;//人初始a的系数为一

    for(int i =2;i<n;i++)
    {
        ans += fib_a(i-1);//累加delta
    }

    return ans;
}

​ 由于第一站没有delta且第二个delta为零,所以n为一或二时特判,从第三站开始累加.特别注意的是数列中数位与i的关系为 数位=i-1

​ x系数的计算完全同理,但是要注意x系数的初始值为0

(3)t与答案的计算

 t = (m - p_a(n-1)*a) / p_x(n-1);//计算t
 int ans = a*p_a(x) + t*p_x(x);//计算答案

​ 既然已经得到每站a与x的系数,那么根据题目,m是n-1站的人数,所以在下标处输入n-1,计算出t后,就很容易得出了.(不过这里好像有点不严谨,n在等于1或2时t是无意义的,测试点应该没有给这种数据,我觉得题目应该让n>=3,不然会有点歧义)

3.源码

#include <iostream>
using namespace std;

int fib_a(int n)
{
    if (n == 1)
        return 1;

    if (n == 2)
        return 0;

    return fib_a(n - 1) + fib_a(n - 2);

}

int fib_x(int x)
{
    if (x == 1)
        return 0;

    if (x == 2)
        return 1;
        
    return fib_x(x - 1) + fib_x(x - 2);
}

int p_a(int n)
{
    int ans = 1;
    for(int i =2;i<n;i++)
    {
        ans += fib_a(i-1);
    }
    return ans;
}

int p_x(int n)
{
    int ans = 0;
    for(int i = 2;i<n;i++)
    {
        ans += fib_x(i-1);
    }
    return ans;
}

int main()
{

    int a, n, m, x, t;
    cin >> a >> n >> m >> x;

    t = (m - p_a(n-1)*a) / p_x(n-1);
    int ans = a*p_a(x) + t*p_x(x);

    cout<<ans;
    return 0;
}

​ 后面也没什么好说的了,送大家一张美图吧

pFbe6ET.jpg