n 个同学去动物园参观,原本每人都需要买一张门票,但售票处推出了一个优惠活动,一个体重为 x 的人可以和体重至少为 2x 配对,这样两人只需买一张票。
现在给出了 n个人的体重,请你计算他们最少需要买几张门票?
输入格式
第一行一个整数 n,表示人数。
第二行 n 个整数,每个整数 ai? 表示每个人的体重。
输出格式
一个整数,表示最少需要购买的门票数目。
输入样例:
6
1 9 7 3 5 5
输出样例:
4
数据范围
30% 的数据:1≤n≤25,1≤ai≤100
60% 的数据:1≤n≤10000,1≤ai≤1000
100%的数据:1≤n≤5?10^5,1≤ai≤10^5
解法一:(双指针)
#include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> #include <math.h> using namespace std; int a[500005]; int main() { //思路:数组排序后用双指针遍历数组,第一个指针 i 从0开始遍历到数组的一半,第二个指针从数组的一步开始遍历到结束 int n; //在i的循环中找满足大于a[i]2倍的元素,找到就ans--,pos指针后移,i指针后移;找不到就 直接 i 指针后移 cin>>n; for(int i=0;i<n;i++){ scanf("%d",&a[i]); } sort(a,a+n); int ans=n; int pos=n/2; for(int i=0;i<n/2;i++){ //数组排序后用双指针遍历数组 while(pos<n&&a[i]*2>a[pos]){ //之所以pos指针不从0开始,是因为每次a[i]找到对应的a[pos]后,即a[i]*2<a[pos] pos++; //由于数组是排序好的,则此时肯定a[i]*2>a[0]~a[pos],也必有a[i+1]*2>a[0]~a[pos] } //故找a[i+1]的配对元素时,pos只需指针后移不用从头开始。 if(pos==n) break; pos++; ans--; } cout<<ans; return 0; }
解法二:(二分)
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int MAX = 6e5 + 5; int a[MAX],n; bool ok(int x) { for(int i = 1; i<=x; i++) { if(a[i+n-x]<a[i]*2) return 0; } return 1; } int main() { cin>>n; for(int i = 1; i<=n; i++) scanf("%d",a+i); sort(a+1,a+n+1); int l=0,r=n/2,mid,ans=0; while(l<=r){ mid = (l+r)>>1; if(ok(mid)) l=mid+1,ans=mid; else r=mid-1; } printf("%d",n-ans); return 0; }