1085 Perfect Sequence (25 point(s))
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 (≤105) is the number of integers in the sequence, and p (≤109) is the parameter. In the second line there are N positive integers, each is no greater than 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
今天敲了1085,涉及的知识点是二分法,一直都能想不出什么好方法,看了书上的思路才知道改怎么敲。 好久没敲了,又有好多小问题了。
先写思路:1、将数组中的元素进行从小到大排序,
2、从首个开始,依次用二分法,找出满足条件的序列的最大个数值。
注意点:每次使用二分法时,头位置以当前max为基础,只找是否存在更大的max。
m*p的范围可能会超出int表示范围,因此用long long。
代码如下,这个通过了,不过后续想的时候觉得还是有问题,好像阴差阳错的给我写对了,我把max初值设为0,实际上,至少也是1,后面在计算队列长度的地方,我也有点想错了,不过这些组合在一起,居然正确了,后面越想越绕,总觉得有点不太对劲。
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define MaxSize 100010
typedef long long LL;
int main()
{
int i,max=0,first,end,mid; //first:头,end,尾,mid,取中,max用来记录最大值
LL N,M,m,p; //m*p可能会超出int范围,因此均用longlong类型
int data[MaxSize];
scanf("%lld %lld",&N,&p);
for(i=0;i<N;i++)
scanf("%d",&data[i]);
sort(data,data+N);
for(i=0;i<N && (i+max)<N;i++) //当剩余元素个数已少于max时,循环结束。
{
first=i+1+max; //看是否有大于max的队列长度存在
end=N;
while(first<=end)
{
mid=(first+end)/2;
M=data[mid];
m=data[i];
if(M<=m*p)
first=mid+1;
else end=mid-1;
}
if(first>i && (first-1-i)>max)
max=(first-1-i);
}
printf("%d",max);
}
后面看了书上的代码,觉得那种方法更好,于是重新写了一遍。
直接计算m*p,求出首个大于该值的数的位置,这样思路比较清晰。
代码如下
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define MaxSize 100010
typedef long long LL;
LL N,M,m,p; //m*p可能会超出int范围,因此均用longlong类型
int data[MaxSize];
//在data[i+1~N-1]中找到第一个大于x的元素,返回其位置
int binarySearch(int i,LL x)
{
if(data[N-1]<=x)
return N;
int first,end,mid;
first=i+1;
end=N-1;
while(first<end)
{
mid=(first+end)/2;
if(data[mid]<=x)
first=mid+1;
else
end=mid; //说明第一个大于x的值在mid之前,包括mid
}
return first;
}
int main()
{
int i,j,max=1;
scanf("%lld %lld",&N,&p);
for(i=0;i<N;i++)
scanf("%d",&data[i]);
sort(data,data+N);
for(i=0;i<N && (i+max)<N;i++) //当剩余元素个数已少于max时,循环结束。
{
j=binarySearch(i,data[i]*p);
//j=upper_bound(data+i+1,data+n,data[i]*p)-data
if((j-i)>max)
max=(j-i);
}
printf("%d",max);
}
binarySearch()可用标准库函数upper_bound(data+i+1,data+n,data[i]*p)-data代替。
做这题的时候,也发现了vc编译器与gcc编译器的一些区别,比如longlong。
完成今日的博客啦
1-24更新:two pointers法
思路,将所有数进行从小到大排序 ,若a[j]<=a[i]*p,则对于任意k>i,a[j]<=a[k]*p成立,所以对应的最大值只会大于等于a[j],
代码如下
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MaxSize 100010
typedef long long LL;
using namespace std;
int main()
{
LL num;
int i,j,n,p,max=1;
int a[MaxSize];
scanf("%d%d",&n,&p);
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
sort(a,a+n);
i=0;j=0;
while(i<n && j<n)
{
while(j<n && a[j]<=(LL)a[i]*p )
{
if((j-i)+1>max)
max=j-i+1;
j++;
}
i++;
}
printf("%d",max);
}