原题链接https://pintia.cn/problem-sets/994805260223102976/problems/994805291311284224
1030 完美数列 (25分)
给定一个正整数数列,和正整数 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
分析:此题主要卡超时,需要算法的优化:
首先要排序,直接用两个循环遍历,会超时,如何优化?假设第二重循环第一次遍历结束后的位置是p,我们可以发现第二重循环如果每次从最小数开始遍历,由于从第二次遍历开始一直到p的几个数一定小于pmin,所以再次将这前几个数进行判断是否小于pmin是无效操作,因此需要记录每次遍历结束后的位置,下一组遍历从上次遍历结束的位置开始和p*min比较。
#include<bits/stdc++.h>
using namespace std;
int main()
{
iostream::sync_with_stdio(0);
int N;
long long p;
cin>>N>>p;
int i,j,k;
long long a[N];
long long t,ans=0,cnt=0,position=0;
for(i=0;i<N;i++)
{
cin>>a[i];
}
sort(a,a+N);
for(i=0;i<N;i++)
{
t=a[i]*p;
for(j=position;a[j]<=t&&j<N;j++)//从上一次结束的position开始,一定要记得加上<N,不然如果所有的数都小于min*p这种情况会错
{
cnt++;
}
if(cnt>ans)
ans=cnt;
if(N-i<=ans)//如果从i开始到结束的数的数量都小于当前的ans,此时ans就是最大的
break;
cnt--;
position=j;//记录结束位置
}
cout<<ans;
return 0;
}