1030. 完美数列(25)
给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列。现在给定参数p和一些正整数,请你从中选择尽可能多的数构成一个完美数列。
输入格式:
输入第一行给出两个正整数N和p,其中N( <= 105)是输入的正整数的个数,p( <= 109)是给定的参数。第二行给出N个正整数,每个数不超过109。
输出格式:
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。
输入样例:
10 8
2 3 20 4 5 1 6 7 8 9
输出样例:
8
分析:我想的是先把这个数列按从小到大排列,然后算出当最小元素是n[0]的时候该完美数列多长,当最小元素是n[1]的时候该完美数列多长。。。。。每次都用max记录下最长的那个完美数列的长度。
但是在找最大元素的过程中我出现了点问题,每次最大元素都要从头开始找,举个栗子,比如当最小元素是a[3]时,我的最大元素就从a[3],a[4],a[5]。。。这样找下去,直到找到了那个最大的比如是a[6],然后继续下一个循环,当最小元素是a[4]的时候,我的最大元素又从a[4],a[5],a[6].。。。这样找下去。这样的结果就是超时,因为时间复杂度达到了O(n^2)
其实观察上面我找的过程发现是有不必要的循环的。当最小元素是a[4]的时候,最大元素可以不用再从a[4]再开始找起的,因为上一个循环已经说明了a[3]*p>=a[6],那么a[4]*p肯定也是大于a[6]的,所以我们从a[7]找起即可。这样时间复杂度就达到了O(n)
最后数组不要用int,因为数字很大,可以用long。
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
int N, p;
long n[100000];
int max=1, i, j=1; //i指向完美数列最小元素,j指向完美数列最大元素,max表示完美数列最大长度
cin >> N >> p;
for (i = 0; i < N; i++)
cin >> n[i];
sort(n, n + N); //排序
for ( i = 0;j<N; i++) //循环从最小元素为第0个开始,当最大元素滑到最后一个循环结束
{
for (; n[i] * p >= n[j]&& j<N; j++); //尽可能的让j往右滑动
if (max < j - i) //判断是否比之前记录的完美数列长度长。
max = j - i;
}
cout << max;
}