P1011 车站 [NOIP 1998 提高组]

题目描述

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

输入格式

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

输出格式

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

输入输出样例 #1

输入 #1

1
5 7 32 4

输出

1
13

说明/提示

对于全部的测试点,保证 1≤a≤20,1≤x≤n≤20,1≤m≤2×104

问题分析 + 求解

已知信息:

  • 发站上车人数 a
  • 车站数 n
  • 终点站人数 m
  • 所求的站点编号 x

我们定义 i:表示第二站上车、下车为 i 人

根据已知信息,我们可以列出表格:

站数(x) 上车人数 下车人数 发车时的人数
1 a / a
2 i i a
3 a+i i 2a+i
4 a+2i a+i 2a+i
5 2a+3i a+2i 3a+2i

我们可以找到规律:

第 x 站时:

发车时的人数 = (x-2)*a+(x-3)*i

经过思考,得出

最后一站的下车人数=倒数第二站发车时的人数

我们可以利用最后一站的下车人数来求 i 的值:

m = (n-3)*a+(n-4)*i

我们可以写出程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
using namespace std;

int main()
{
int a, n, m, x;
cin >> a >> n >> m >> x;

int i = 0;
//求i
while(true)
{
if (((n - 3) * a + (n - 4) * i) == m)
{
break;
}
i++;
}

int rs = (x - 2) * a + (x - 3) * i;//代入公式
cout << rs;
}

可以注意到,这个程序求 i 的值用的是暴力求解法。

一个 TLE,一个 WA,其他全过

所以,这个结果也是意料之中

orz

但是除了暴力方法以外,我实在想不到别的方法了。。。

但是,我的代码是效率低,出现 TLE 是意料之中,但是这个 WA 又是怎么回事?

这就不得而知了。。。

但是这个程序还是可以优化的:

  1. 优化 i 的求解方法:暴力枚举可以,但 二分查找更快。

  2. 增加边界保护:防止 x = 1 或 x = 2 时出现计算错误(尽管题目给的范围一般不会触发)。

但是,考虑到 i 的取值范围很小,所以说二分查找可能不比暴力枚举快多少。

所以我们只针对 x=1,x=2 的情况进行优化。

但是,加了 if 进行特殊输出后还是有一个 WA,不管了。

什么时候学了递推再回来改进吧~~