PAT自主训练记录 甲级A1085/乙级B1030 Perfect Sequence/完美数列

A1085 Perfect Sequence (25分)

题目描述

Given a sequence of positive integers and another positive integer p. The sequence is said to be a perfect sequence if M≤m×p where M and m are the maximum and minimum numbers in the sequence, respectively.
Now given a sequence and a parameter p, you are supposed to find from the sequence as many numbers as possible to form a perfect subsequence.

Input Specification:

Each input file contains one test case. For each case, the first line contains two positive integers N and p, where N (≤ 10 ​ 5 10​^5 105) is the number of integers in the sequence, and p (≤ 1 0 9 10^9 109) is the parameter. In the second line there are N positive integers, each is no greater than 1 0 9 10^9 109.

Output Specification:

For each test case, print in one line the maximum number of integers that can be chosen to form a perfect subsequence.

Sample Input:

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

Sample Output:

8


题目大意

从N个正整数中选择若干个数,使得选出的这些数中的最大值不大于最小值的p倍。找出选出的数最多可能有多少个

思路
将给的数组按照递增排序,在这个递增的数列中确定一个最小值a[i],最大值a[j]使得a[j]≤a[i]*p成立,且j-i是所有满足条件的情况中的最大值。
(每找到一种满足条件的情况都要更新最大值)

注意点

  • a[i]*p≤ 1 0 18 10^{18} 1018,所以这里需要注意数据类型设置为long long。(也可以一开始就将序列中的数直接定义为long long型)
  • 单独判断当序列中的所有的数都不超过a[i]*p的情况
  • 本题的数据用双重遍历是肯定会超时的

过程中犯的错误

  • 刚开始头脑简单(还心想着这不是贪心题嘛,这么简单)写代码的时候无形中将最小的数确定为排序后数组的a[0],求的是对于最小数是a[0]的情况下的结果
    (意识到错误之后并没能立马反应过来用二分法写应该是怎么样的一个思路)
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#define Maxn 100001
using namespace std;

int a[Maxn];

int main(){
    int N,p;
    scanf("%d%d",&N,&p);
    for(int i=0;i<N;i++)
        scanf("%d",&a[i]);
    sort(a,a+N);
    int res=0;
    for(int i=N-1;i>=0;i--){
        if(a[i]*a[0]<=p){
            res=i+1;
            break;
        }
    }
    printf("%d\n",res);
    return 0;
}

最终正确代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#define Maxn 100001
using namespace std;

int n,p,a[Maxn];

//在[i+1,n-1]范围内查找第一个大于x的数字的位置(所以最终的长度是函数返回值-i)
int binaryfind(int i,long long x){
    int left=i+1,right=n-1,mid;
    if(a[n-1]<=x)
        return n;
    else{
        while(left<right){
            mid=(left+right)/2;
            if(a[mid]<=x){
                left=mid+1;
            }else{
                right=mid;
            }
        }
    }
    return left;//while结束时left=right,因此返回left或者right都是可以的
}

int main(){
    scanf("%d%d",&n,&p);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    sort(a,a+n);
    int res=1;
    for(int i=0;i<n;i++){
        int temp=binaryfind(i,(long long) a[i]*p);
        res=max(res,temp-i);//更新最大的长度
    }
    printf("%d\n",res);
    return 0;
}

算法笔记里的另一个写法

书上将二分查找直接用upper_bound函数进行代替,使得代码简介很多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值