1085 Perfect Sequence

题意:在给定的n个数中选出m个数(数的大小不超过10^9),记这m个数中的最大值为Max,最小值为Min,要求满足Max<=p*Min(p<=10^9),问所有满足条件的方案中m最大是多少。问题相当于:在一个给定的递增序列中,确定一个左端点a[i]和右端点a[j],使得a[j]<=a[i]*p成立,求j-i的最大值。

思路:

做法1:

首先需要立刻反应的是,p,Min均存储为int型整数,p*Min的值可能会溢出,因此应该(long long)p*Min,或者把输入数据全都定义成long long ing型也可以;然后,对于给定的序列,先从小到大排序。如下,定义指针low=0,high=n-1,maxidx=high(指向子序列的最大值)

1     2     3     4     5     6     7     8     9     20

low                                                         high/maxidx

第1次查找时(即low==0时),进入语句1,当退出while循环时,maxidx恰指向符合要求的最大值处,如下,

   2     3     4     5     6     7     8     9     20

low                                       maxidx      high

第2,3...次查找时,根据条件Max<=p*Min,随着Min的增大,显然满足条件的最大值Max肯定在第一次指向的位置maxidx之后了,因此,从maxidx开始向右遍历,即进入语句2。

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=100005;
int seq[N];

int main()
{
    int n,p;
    scanf("%d%d",&n,&p);
    for(int i=0;i<n;i++)
        scanf("%d",&seq[i]);
    sort(seq,seq+n);
    int low=0,high=n-1;
    int maxSize=1;
    int maxidx=high;
    while(low<high){
        if(low==0){
            while(seq[maxidx]>(long long)seq[low]*p)//语句1
                maxidx--;
        }else{
            while(seq[maxidx]<=(long long)seq[low]*p && maxidx<=high)//语句2
                maxidx++;
            maxidx--;
        }
        if(maxidx-low+1>maxSize) maxSize=maxidx-low+1;
        low++;
    }
    printf("%d",maxSize);
    return 0;
}

 

 做法2:使用upper_bound()函数。简单说明一下这个函数,该函数在<algorithm>下,函数接口为  ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value ); 函数返回区间 [first,last) 内指向首个大于value的元素的迭代器,若不存在这样的元素,则返回尾迭代器last。另外注意要求该区间内的元素有序。如下,

vector<int> vec={1,2,3,4,5,6};
vector<int>::iterator it=upper_bound(vec.begin(),vec.end(),5);//C++11之后可用auto关键字
if(it!=vec.end()) 
  printf("I find it,%d\n",*it);//返回6 else
  printf("Such element does't exist\n"); it=upper_bound(vec.begin(),vec.end(),10); if(it!=vec.end())
  printf("I find it,%d\n",*it); else
  printf("Such element does't exist\n");//不存在大于10的数

因此,本题的做法就是,顺序遍历有序数组,对于每一个seq[i],寻找首个seq[j],使其seq[j]>seq[i]*p,然后记录并比较区间的长度j-i即可,代码如下:

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
    int n,p;
    scanf("%d%d",&n,&p);
    vector<int> seq(n);
    for(int i=0;i<n;i++)
        scanf("%d",&seq[i]);
    sort(seq.begin(),seq.end());
    int maxSize=1;
    for(auto it=seq.begin();it!=seq.end();it++){
        auto maxIter=upper_bound(it+1,seq.end(),(long long)*it*p);//第一个*是解引用,第二个*是乘号
        if(maxIter-it>maxSize) maxSize=maxIter-it;
    }
    printf("%d\n",maxSize);
    return 0;
}

 

转载于:https://www.cnblogs.com/kkmjy/p/9545577.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值