1060 爱丁顿数
英国天文学家爱丁顿很喜欢骑车。据说他为了炫耀自己的骑车功力,还定义了一个“爱丁顿数” E ,即满足有 E 天骑车超过 E 英里的最大整数 E。据说爱丁顿自己的 E 等于87。
现给定某人 N 天的骑车距离,请你算出对应的爱丁顿数 E(E ≤ N)。
输入格式:
输入第一行给出一个正整数 N (N ≤ 105),即连续骑车的天数;第二行给出 N 个非负整数,代表每天的骑车距离。
输出格式:
在一行中给出 N 天的爱丁顿数。
输入样例:
10
6 7 6 9 3 10 8 2 7 8
输出样例:
6
思路:算法题,首先明确一点,必须有
E
E
E 天骑车超过
E
E
E 英里,也就是大于,没有等于号。
杂乱的数据不易看出规律,要进行排序,至于是升序还是降序,实现的原理都一样,这里按照升序(非降序)进行分析
对于有
N
N
N 个数的非降序序列
a
[
0
]
a[0]
a[0]
a
[
1
]
a[1]
a[1]
a
[
2
]
a[2]
a[2]
a
[
3
]
a[3]
a[3]
a
[
4
]
a[4]
a[4]
a
[
5
]
a[5]
a[5]
.
.
.
...
...
a
[
N
−
1
]
a[N-1]
a[N−1]
不妨定
a
[
j
]
a[j]
a[j] 为爱丁顿数,
N
−
j
−
1
N-j-1
N−j−1 是
a
[
j
]
a[j]
a[j] 右侧剩余整数个数(每个都大于等于
a
[
j
]
a[j]
a[j])
显然
j
j
j 越大,
a
[
j
]
a[j]
a[j] 也可能越大,所确定的爱丁顿数就可能越大
当
a
[
j
]
a[j]
a[j] 可能为爱丁顿数时,一定满足
a
[
j
]
≤
N
−
j
−
1
a[j]≤N-j-1
a[j]≤N−j−1(爱丁顿数小于等于剩余天数)
那么不妨一直向右遍历搜寻,看什么时候该不等式不成立
假定当找到
a
[
3
]
a[3]
a[3] 时,
a
[
3
]
a[3]
a[3]
>
N
−
3
−
1
>N-3-1
>N−3−1,即爱丁顿数大于剩余天数,这显然不合题意
于是回溯到
a
[
2
]
a[2]
a[2] ,此时必定有
a
[
2
]
a[2]
a[2]
≤
N
−
2
−
1
≤ N-2-1
≤N−2−1,故
a
[
2
]
a[2]
a[2] 可能为爱丁顿数
但爱丁顿数不一定就是序列中的数,现在我们知道最多可选
N
−
2
−
1
N-2-1
N−2−1 天,故
E
≤
N
−
2
−
1
E≤N-2-1
E≤N−2−1
举例来进一步思考,例如,对于
8
1 2 6 6 6 6 6 6
回溯找到2后,2后边有6个数,且2的下一个数是6,如果E就等于6,显然是错误的
故回溯后的下一个数也是一个需要考虑的因素,由此得
E
=
m
i
n
E = min
E=min{
N
−
j
−
1
,
N-j-1,
N−j−1,
a
[
j
+
1
]
−
1
a[j+1]-1
a[j+1]−1},所以
E
=
m
i
n
E=min
E=min{
8
−
1
−
1
,
6
−
1
8-1-1,\ 6-1
8−1−1, 6−1}
=
5
=5
=5
注意,存在一些特殊情况,如
3
1 1 1
此时 E = 0 ,为正解
3
0 0 0
此时按照算法算得 E = -1 ,应输出0
以及对于各种
a
[
0
]
≥
N
a[0] ≥ N
a[0]≥N 的情况,如
5
5 6 7 8 9
和
5
8 8 8 8 8
应该直接对应
N
N
N 进行输出,前者
E
=
N
−
1
=
4
E=N-1=4
E=N−1=4,后者
E
=
N
=
5
E=N=5
E=N=5
#include <stdio.h>
#include <math.h>
#include <algorithm>
int n, E, j = 0, a[100000] = { 0 };
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
std::sort(a, a + n);
while (a[j] <= n - j - 1) j++;
j--; //回溯到上一个数
if (a[0] >= n) a[0] == n ? E = n - 1 : E = n;
else E = fmin(n - j - 1, a[j + 1] - 1);
E > 0 ? printf("%d", E) : printf("0"); //E为0或负数时输出0
return 0;
}