题目来源:PAT (Basic Level) Practice
给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列。
现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。
输入格式:
输入第一行给出两个正整数 N 和 p,其中 N(≤105)是输入的正整数的个数,p(≤109)是给定的参数。第二行给出 N 个正整数,每个数不超过 109。
输出格式:
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。
输入样例:
10 8
2 3 20 4 5 1 6 7 8 9
输出样例:
8
思路:
1. 本题的意思从给定的n个数的数列中找出长度最大的一个子数列使得子数列的最大值M和最小值m满足M<=mp,即完美数列;
2. 首先对题目给定的数列进行从小到大排序,便于快速找出最大值M和最小值m;
3. 使用滑动窗口,设 i 为滑动窗口的左端,j 为滑动窗口的右端,那么窗口内的最小值为v[i],窗口内的最大值为v[j];
a. 若 v[i]*p >= v[j] ,则窗口内的数组成的数列是完美数列,则记录这个长度;窗口右端右移;
b. 若 v[i]*p < v[j] ,则窗口内的数组成的数列不是完美数列,窗口左端右移;
4. 从记录的完美数列窗口长度中找出一个最大值即为答案;
5. p 、 m 、M 都在int 长度范围内,但是p*m会超出int长度范围,所以p和m在相乘之前应该强制转化为 long long类型,或者在定义时定义为 long long 类型;
//1030 完美数列
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
int main()
{
int n,p,i,j;
cin>>n>>p;
vector<int> v(n);
for(i=0;i<n;i++) //输入
cin>>v[i];
sort(v.begin(),v.end()); //从小到大排序
int ans=1;
for(i=0,j=0;i<n&&j<n;) //设置滑动窗口的左端为i,右端为j
{
if((long long)v[i]*p>=v[j]) //完美数列
{
ans=max(ans,j-i+1); //记录窗口长度
j++;
}
else
i++;
}
cout<<ans<<endl;
return 0;
}