给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列。
现在给定参数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
思路:先把数列从小到大排序,然后从最小的那个数开始乘起,一直找到>m*p的最大数,此时记下长度,然后转到下一个较小的数字进行计算,最终得到大的数,但是这样会导致第四个测试点超时,普通代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int N,num;
long long p;
vector <int> sequence;
cin >> N >> p;
for (int i = 0; i < N; i++)
{
scanf("%d", &num);
sequence.push_back(num);
}
sort(sequence.begin(), sequence.end());
int count=1,maxsum=1,j;
for (int i = 0; i < sequence.size() - 1; i++)
{
j = i + 1;
while (j<sequence.size()&&sequence[i] * p >= sequence[j])
{
count++;
j++;
}
if (count>maxsum)
maxsum = count;
count = 1;
}
printf("%d", maxsum);
return 0;
}
超时说明这个算法还不够快,怎么改进呢?我们在前一个最大数的基础上已经得到了当前最大的数列,那么下一个数列肯定有一部分是它的子序列,所以我们就不从下一个数开始寻找最大数,我们转向j=i+maxsum开始算起。只需要改动两个地方就可以了,如下所示:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int N,num;
long long p;
vector <int> sequence;
cin >> N >> p;
for (int i = 0; i < N; i++)
{
scanf("%d", &num);
sequence.push_back(num);
}
sort(sequence.begin(), sequence.end());
int count=1,maxsum=1,j;
for (int i = 0; i < sequence.size() - 1; i++)
{
j = i + maxsum;
while (j<sequence.size()&&sequence[i] * p >= sequence[j])
{
count = j - i + 1;/
j++;
}
if (count>maxsum)
maxsum = count;
count = 1;
}
printf("%d", maxsum);
return 0;
}