P1011 [NOIP1998 提高组] 车站

题目描述

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

输入格式

输入只有一行四个整数,分别表示始发站上车人数 a,车站数 n,终点站下车人数 m 和所求的站点编号 x。

输出格式

输出一行一个整数表示答案:从 x 站开出时车上的人数。

输入输出样例

输入        

5 7 32 4

输出

13

思路

  1. 先根据题目所给的上、下车规律找到人数变化的规律
  2. 第一站上车 a 人,下车 0 人,所以净上车人数(上车的人数 - 下车的人数)为 a

  3. 第二站上下车人数相等,假设上、下车人数为 b 人,所以净上车人数为 0

  4. 第三站上车人数等于前面两站上车人数之和,下车人数为前一站的上车人数,所以第三站上车人数为 a+b,下车人数为 b,所以净上车人数为 a

  5. 第四站上车人数为第二站和第三站上车人数之和,下车人数是第三站上车人数,上车人数 a+2b,下车人数 a+b,所以净上车人数为 b

  6. 第五站上车人数为第三站和第四站上车人数之和,下车人数是第四站上车人数,上车人数 2a+3b,下车人数 a+2b,所以净上车人数为 a+b

  7. 以此类推,第六站净上车人数为 a+2b,第七站净上车人数为 2a+3b...... 

将各个站的净上车人数做成表格更加清晰明了 ,我们可以发现某一站的净上车人数等于前面两站净上车人数之和,类似斐波那契数列。但又不是完全一样,比如第四站的净上车人数就不等于第二站和第三站的净上车人数之和。所以我们还应该做些许改动,让其与斐波那契数列有着相同的规律

站数第一站第二站第三站第四站第五站第六站第七站
净上车人数a0aba+ba+2b2a+3b

我们将净上车人数分开来看,如果净上车人数里面有 a,就放入数列 a,没有就把 0 放入数列 a 中,如果净上车人数里面有 b,就放入数列 b,没有就把 0 放入数列 b 中,然后再观察它们的变化

 

站数第一站第二站第三站第四站第五站第六站第七站
数列 aa0a0aa2a
数列 b000bb2b3b

我们可以发现数列 a 与数列 b 在前四站不符合斐波那契数列的规律,而从第五站开始,当前站的数列 a 与数列 b 都为前面两站之和,所以可以使用递归来解决此问题,对数列 a 与数列 b 都使用递归,如果传进来的参数小于等于4,就返回它们的值,如果大于4,就返回参数-1的值 + 参数-2的值

代码 

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int n = sc.nextInt();
        int m = sc.nextInt();
        int x = sc.nextInt();
        int num1 = 0;  //储存数列 a 的前n-1 项和
        int num2 = 0;  //储存数列 b 的前n-1 项和
        int x1 = 0, x2 = 0;  //记录第 x 站时,车上的人数
        for (int i = 1; i < n; i++) {
            num1 += f1(i);
            num2 += f2(i);
            if (i == x) {
                x1 = num1;
                x2 = num2;
            }
        }
        int b = (m - num1 * a) / num2;  //求出第二站上车的人数 b
        System.out.println(x1 * a + x2 * b);
    }

    public static int f1(int n) {  //数列 a 的递归
        if (n == 1 || n == 3) {
            return 1;
        }
        if (n == 2 || n == 4) {
            return 0;
        }
        return f1(n - 1) + f1(n - 2);
    }

    public static int f2(int m) {
        if (m == 1 || m == 2 || m == 3) {  //数列 b 的递归
            return 0;
        }
        if (m == 4) {
            return 1;
        }
        return f2(m - 1) + f2(m - 2);
    }
}

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值