题目如下:
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 9Sample Output:
8
题目要求从给定序列中选取子序列,使得序列的最小值m、最大值M满足:M≤m*p,其中p为一个给定的正整数,输出能找到的最长子序列长度。
这道题一个很自然的思路就是设立一个头指针cur1,尾指针cur2,将序列按照升序排列,让cur2从最后一个元素向前指,cur1遍历从第一个元素到cur2的位置,找到合适的m时停下,记录长度,这样会有一个case超时,解决方法是让cur1从前到后遍历,cur2采用二分查找。
如果找到的位置使得M<m*p,说明M还可以更大,可以继续查找右半部分;如果M>m*p,说明M偏大,应该去左半部分找更小的;如果M=m*p,说明找到了合适的位置。在查找结束后,记录长度即可。
这段代码参考了Yangsongtao1991。
#include <iostream> #include <vector> #include <algorithm> #include <stdio.h> using namespace std; int main() { int n,p; scanf("%d%d",&n,&p); vector<long> seq(n); for(int i = 0; i < n; i++) scanf("%ld",&seq[i]); sort(seq.begin(),seq.end()); int maxcount = 0, down = 1; for(int i = 0; i < n; i++) { long mp = p * seq[i]; if(mp >= seq[n-1]) // 如果最大的元素都≤m*p,则从当前位置到最后全部计数。 { if(maxcount < n - i){ maxcount = n - i; } break; } int up = n-1; while(up > down) { // 二分查找,结束条件为上界≤下界,根据mid处的乘积判定。 // 现在是确定了m,要找M,如果找到的位置<mp,说明M可能可以更大,向右找;如果>mp,说明M偏大,向左找。 // 如果当前位置恰好满足,则说明已经找到了最长满足要求的位置。 int mid = (up + down)/2; if(seq[mid] > mp) up = mid; else if(seq[mid] < mp) down = mid + 1; else { down = mid + 1; break; } } if(down - i > maxcount) maxcount = down - i; } printf("%d ",maxcount); return 0; }