题目
给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列。
现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。
输入格式:
输入第一行给出两个正整数 N 和 p,其中 N(≤10 ^ 5)是输入的正整数的个数,p(≤10 ^ 9)是给定的参数。第二行给出 N 个正整数,每个数不超过 10 ^ 9。
输出格式:
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。
输入样例:
10 8
2 3 20 4 5 1 6 7 8 9
输出样例:
8
思路
先排序,然后找最长区间。
对于每个a[i],寻找符和条件的最长跨度a[j]。对于区间跨度小于当前最大值的,就无需判断。
测试点0错误
一开始,测试点0错误,原因是将题目条件M ≤ mp转换成了除法M / m <= p,但整数做除法时结果存在误差!应当保留小数部分,转换为float除法:M * 1.0 / m <= p
例如,测试用例:
2 2
2 5
M=5,m=2,M / m = 2 <=p,M * 1.0 / m = 2.5 > p
测试点4错误
但测试点0通过后,测试点4仍然超时。在网上查到有人也遇到同样情况,只不过换一种遍历方法就能通过,下面是两种方法(一开始用的方法一)。
算法
方法一:while循环从右往左搜索,找第一个符合条件的。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n, p;
cin >> n >> p;
vector
PAT乙级真题:完美数列的C++实现与超时解决

该博客介绍了PAT乙级编程竞赛中的一道真题,涉及如何构建完美数列。博主分享了错误思路,即在判断条件时误将M * m <= p转换为M / m <= p,导致测试点0错误。修正后的正确思路是对数列排序,查找满足条件的最大跨度。此外,博主还提到在测试点4出现超时问题,对比了两种遍历方法:从右往左和从左往右,发现后者在大规模测试用例中表现更优,认为这是题目设计的一个‘神坑’。
最低0.47元/天 解锁文章
386





