PTA:B1030/A1085 完美數列。c++

完美數列

題面:

給定一個正整數數列,和正整數 p,設這個數列中的最大值是 M,最小值是 m,如果 M≤mp,則稱這個數列是完美數列。
現在給定參數 p 和一些正整數,請你從中選擇儘可能多的數構成一個完美數列。

輸入第一行給出兩個正整數 N 和 p,其中 N(≤105​​)是輸入的正整數的個數,p(≤10​9​​)是給定的參數。第二行給出 N 個正整數,每個數不超過 10​9​​。

在一行中輸出最多可以選擇多少個數可以用它們組成一個完美數列。

sample input:

10 8
2 3 20 4 5 1 6 7 8 9

sample output:

8

思路:
  • 因爲考慮到選出序列的最大值和最小值,所以首先將輸入的序列進行排序,方便之後的處理
  • 在一個給定的遞增序列中找出左邊界和右邊界,保證滿足左端點值不超過右端點值*p,並且滿足右端點與左端點的距離最大
  • 可以使用二重循環進行枚舉,但是給定的參數的值比較大,如果使用循環會爆掉,同時也要注意,使用int也會超,要用long long 來表示乘法之後的結果
  • 使用二分查找來降低時間複雜度,由於是遞增序列,所以如果改位置的值比預想的值小,說明下一次要在mid的後邊進行查找,如果比預想值大,那就在mid的前半段進行查找
  • 代碼中的search函數就是尋找符合要求的值的位置的函數,也可以使用upper_bound函數來代替,這樣可以減少代碼量
AC代碼
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
int a[100001]; 
int n;
int search(int i,long long x)//對於數組尋找第一個大於x的位置 
{
 int l=i+1,r=n-1,mid=0; 
 if(a[n-1]<=x) return n;//所有數都不大於
 while(l<r)
 {
  mid=(l+r)/2;
  if(a[mid]<=x)//說明大於mid的肯定在右邊/後邊
   l=mid+1;
  else r=mid; 
  } 
 return l;
}
int main()
{
 int p;
 cin>>n>>p;
 for(int i=0;i<n;i++)
 cin>>a[i];
 sort(a,a+n);
 int ans=1;
 for(int i=0;i<n;i++)
 {
  //查找第一個超過a[i]*p的數,返回他的位置
  int pos=search(i,(long long)a[i]*p);
  ans=max(ans,pos-i); 
 }
 cout<<ans<<endl;
 return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章