输入第一行给出两个正整数N和p,其中N(<= 105)是输入的正整数的个数,p(<= 109)是给定的参数。第二行给出N个正整数,每个数
不超过109。
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。
10 8 2 3 20 4 5 1 6 7 8 9
8
void helper_6(int N,int p) { int* arr=new int[N]; for(int i=0;i<N;i++) { cin>>arr[i]; } sort(arr,arr+N); int res=0; for(int i=0;i<N;i++) { for(int j=i+res;j<N;j++) { if (arr[j] > arr[i] * p) break; res++; } } cout<<res<<endl; } int main() { int num,p; while(cin>>num>>p) { helper_6(num,p); } return 0; }
#include<stdio.h> void qsort(int num[],int L,int R)//快速排序 { if(L<R) { int i=L; int j=R; int k=num[L]; while(i<j) { while(i<j&&num[j]>=k) j--; if(i<j) num[i++]=num[j]; while(i<j&&num[i]<k) i++; if(i<j) num[j--]=num[i]; } num[i]=k; qsort(num,L,i-1); qsort(num,i+1,R); } } int main() { double p; int i,j,N,num[100000],count=0; scanf("%d %lf",&N,&p); for(i=0;i<N;i++) scanf("%d",&num[i]); qsort(num,0,N-1); for(i=0;i<N;i++) for(j=i+count;j<N;j++) { if(num[j]>num[i]*p) break; count++; } printf("%d",count); return 0; }
这道题目首先需要考虑选择尽可能多的数构成一个完美数列。而它的条件又仅需要最大,最小值参与,比较能联想到需要用到排序,接下来按照循环去做。
不考虑排序,仅考虑这个循环查找算法,它的时间复杂度达到了,如何优化它是接下来考虑的问题。这里有介绍两个方法二分查找和双指针法。
二分查找的基本思路不用再说了,但是在实践中注意几个细节有利于简化思路:
虽然查找条件while(low <= high)
也可以写成while(low < high)
,但是两者有区别,当前者未找到时,low
和high
处于第一次low>high
的状态;而后者处于low==high
的状态。这里统一下,用第一种方法,后面会说为什么这么做。
总是在和之间查找元素。对于mid判断完毕后,不用再包含mid。
二分查找(查找不到返回-1)
//A为递增数列,x为欲查询的数,函数返回查找到的索引,未查找到返回-1 int binarySearch(int a[],int low,int high,int x){ while (low <= high){ int mid = low + (high - low) / 2; if (a[mid] < x){ low = mid + 1; } else if (a[mid] > x){ high = mid - 1; } else return mid; } return -1; }
基于二分查找,可以进一步扩展两个方法。
查找第一个大于或等于x的元素位置
查找第一个大于x的元素位置
查找第一个大于或等于x的元素位置
//A为递增数列,x为欲查询的数,函数返回查找到的索引,未查找到返回-1 int binarySearch(int a[],int low,int high,int x){ while (low <= high){ int mid = low + (high - low) / 2; if (a[mid] < x){ low = mid + 1; } else if (a[mid] >= x){// <-- if (a[mid] > x) high = mid - 1; } // else return mid; } return low;// <-- return -1 }
这里修改了三处:第一,修改了return -1
为return low
;第二,修改条件if (a[mid] > x)
为if (a[mid] >= x)
;第三,删除条件return mid
。
分析:
查找第一个大于或等于x的元素位置,将条件if (a[mid] > x)
改为if (a[mid] >= x)
,对于只要大于等于x的位置,都在其左半部分查找(降低high)。该条件会导致高位high不断向左靠近,直到最后一个小于x的位置。
最终,high和low均指向最后一个小于x的位置。这里要解释下上面为什么while条件中使用(low<=high)
,当while (low == high)
成立,条件满足if (a[mid] < mp) low = mid + 1;
,所以最终能通过low返回第一个大于等于x的索引位置。其目的就是为了保证low在等于high(指向最后一个小于x的位置)时,仍可以多一步运算而指向第一个大于等于的元素。
查找第一个大于x的元素位置
同上。只不过等于号加在另一个条件中。
//A为递增数列,x为欲查询的数,函数返回查找到的索引,未查找到返回-1 int binarySearch(int a[],int low,int high,int x){ while (low <= high){ int mid = low + (high - low) / 2; if (a[mid] <= x){ low = mid + 1; } else if (a[mid] > x){ high = mid - 1; } } return low; }
与上面唯一的不同在于将等号放在了条件if (a[mid] <= x)
中,但是却将最终结果变成了查找第一个大于x的元素位置。
分析:
此时,对于小于等于x的情况,都是在右半部分查找(提高low),该条件会导致低位low不断向右靠近,直到最后一个小于或等于x的位置。
当(low==high)时,将low = mid+1
,最终将返回第一个大于x的位置索引。
有了以上二分法的基础,那么这道题目可以总结为,查找最大的小于等于mp的数,这个问题可以转为上面的查找第一个大于mp的元素位置 - 1就得到了最大的小于等于x的数位置。
*注意: *的范围虽然不超过int
范围,但是mp
的范围是可能溢出的,所以这里选用long long
作为数据类型。
/* * app=PAT-Basic lang=c++ * https://pintia.cn/problem-sets/994805260223102976/problems/994805291311284224 */ #include <cstdio> #include <algorithm> using namespace std; const int maxn = 100010; int a[maxn] = {}; int N, p; /* 二分法: * 注意数据边界,10^9很容易超过int范围,所以用long long */ int binarySearch(int low,long long m){ int high = N - 1; while (low <= high){ int mid = low + (high - low) / 2; if (a[mid] <= m*p) low = mid + 1; else high = mid - 1; } return low; } int main() { scanf("%d%d", &N, &p); for (int i = 0; i < N; i++){ scanf("%d",&a[i]); } sort(a,a+N); int maxNum = 0; for (int i = 0; i < N; i++){ int low = binarySearch(i, a[i]); maxNum = low - i > maxNum ? low - i : maxNum; } printf("%d",maxNum); return 0; }
使用双指针法时,有一个超时点,需要优化,因为是从i+1开始向后递增的,其实这个值不需要每次循环都重新赋值i+1,因为数组是递增的。所以,对于后面的数来说,a[high]要么是第一个大于mp的数,要么是小于等于mp的数。
/* * app=PAT-Basic lang=c++ * https://pintia.cn/problem-sets/994805260223102976/problems/994805291311284224 */ #include <cstdio> #include <algorithm> using namespace std; const int maxn = 100010; int a[maxn] = {}; int main() { /*双指针法*/ int N, p; long long mp; scanf("%d%d",&N,&p); for (int i = 0; i < N;i++){ scanf("%d", &a[i]); } sort(a, a + N); int max = 0,high = 0;//high赋值一次即可 for (int i = 0; i < N;i++){ mp = (long long)a[i] * p; while (high < N){ if (a[high] <= mp) high++;//对于后面的数来说,a[high]要么是第一个大于mp的数,要么是小于等于mp的数。 else break; } max = max > high - i? max : high - i; } printf("%d",max); return 0; }
木有人手写二分了嘛 #include <bits/stdc++.h> using namespace std; const int N = 1e5+10; typedef long long LL; LL arr[N]; int binSearch(int l, int r, LL x){//寻找小于等于x的最大值 while(l < r){ int mid = (l+r+1)>>1; if(arr[mid]<=x) l = mid;else r = mid - 1; } return l; } int main(){ int n,p,ans = 0; scanf("%d%d",&n,&p); for(int i = 0; i < n; i++) scanf("%lld",&arr[i]); sort(arr,arr+n); for(int i = 0; i < n; i++){ int j = binSearch(i,n-1,p*arr[i]); //int j = upper_bound(arr+i,arr+n,p*arr[i])-arr; //j--; ans = max(ans,j-i+1); } printf("%d\n",ans); return 0; }
import java.util.Arrays;
import java.util.Scanner;
/**
* 完美数列
* 题目描述
* 给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列。
* 现在给定参数p和一些正整数,请你从中选择尽可能多的数构成一个完美数列。
* 输入描述:
* 输入第一行给出两个正整数N和p,其中N(<= 105)是输入的正整数的个数,p(<= 109)是给定的参数。第二行给出N个正整数,每个数
* 不超过109。
* 输出描述:
* 在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。
* 输入例子:
* 10 8
* 2 3 20 4 5 1 6 7 8 9
* 输出例子:
* 8
*
* @author shijiacheng
* @date 2018/1/29
*/
public class B1020PerfectSequence {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int p = sc.nextInt();
int[] array = new int[N];
for (int i = 0; i < N; i++) {
array[i] = sc.nextInt();
}
Arrays.sort(array);
int length = 0;
for (int i = 0; i < N; i++) {
for (int j = i + length; j < N; j++) {
if (array[j] > array[i] * p)
break;
length++;
}
}
System.out.println(length);
}
}
//方法一,用二分查找法 #include <cstdio> #include <algorithm> using namespace std; const int maxn = 100010; int n, p, a[maxn]; int main() { scanf("%d%d", &n, &p); for(int i = 0; i < n; i++){ scanf("%d", &a[i]); } sort(a, a+n); int ans = 1; for(int i = 0; i < n; i++){ int j = upper_bound(a+i+1, a+n, (long long)a[i]*p) - a; ans = max(ans, j-i); } printf("%d\n", ans); return 0; } //方法二 用two pointers #include <cstdio> #include <algorithm> using namespace std; const int maxn = 100010; int n, p, a[maxn]; int main() { scanf("%d%d", &n, &p); for(int i = 0; i < n; i++){ scanf("%d", &a[i]); } sort(a, a+n); int i = 0, j = 0, count = 1; while(i < n && j < n){ while(j < n && a[j] <= (long long)a[i]*p){ count = max(count, j - i +1); j++; } i++; } printf("%d\n", count); return 0; }
最重要的是,在第二层循环里,把 循环变量 附上的初值 为 第一层循环变量的值 再 加上已得到最大的数据长度。 减少 程序 运行时间。#ifndef Basic_Level_1020_CPP#define Basic_Level_1020_CPP#include<vector>#include<stdio.h>#include<algorithm>using namespace std;bool compare(const int &a,const int &b){return a<b;}int main(){int N,p;scanf("%d %d",&N,&p);vector<int> numbers;for(int i=0;i<N;++i){int temp;scanf("%d",&temp);numbers.push_back(temp);}sort(numbers.begin(),numbers.end(),compare);vector<int> times;int t_max=0;for(vector<int>::iterator a=numbers.begin();a<numbers.end();++a){for(vector<int>::iterator b=a+t_max;b<numbers.end();++b){int now=(*b);if((*a)*p<now){break;}t_max++;}times.push_back(t_max);}sort(times.begin(),times.end(),compare);int max_times;max_times=(*(times.end()-1));printf("%d\n",max_times);return 0;}#endif // Basic_Level_1020_CPP
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { long N,p,temp; cin>>N>>p; vector<long> lvec; for(long i=0; i<N; i++) { cin>>temp; lvec.push_back(temp); } sort(lvec.begin(),lvec.end()); long max = 0; for(long i=0; i<N; i++) { for( long j=i+max; j<N; j++) { if(lvec[j] > lvec[i]*p) break; max++; } } cout<<max; return 0; }
#include<iostream> #include<algorithm> using namespace std; int a[100010]; int main() { int n,p; cin>>n>>p; for(int i=0;i<n;i++) { cin>>a[i]; } sort(a,a+n); int m=1; for(int i=0;i+m<n;i++)//寻找所有可能的完美数列 { if(i!=0&&a[i]==a[i-1]) { continue; } for(int j=i+m;j<n;j++) { if(a[j]>a[i]*p) { break; } m++; } } cout<<m<<endl; }
#include<bits/stdc++.h> using namespace std; int main(){ int n,p; cin >> n >> p; long long num[n]; for(int i=0;i<n;i++) cin >> num[i]; sort(num,num+n); int i=0,j=0,max=0; while(i<n&&i>=j){ if(num[j]*p>=num[i]){ if(i-j+1>max) max = i-j+1; i++; } else j++; } cout << max; return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=100000; int arr[MAXN]; int main(){ int n=0,p=0; cin>>n>>p; for(int i=0;i<n;i++){ scanf("%d",&arr[i]); } sort(arr,arr+n); int j=0; int count=0,count_temp=0; for(int i=0;i<n-count;i++){ count_temp=0; for(;j<n;j++){ if((long long)arr[i]*p<arr[j]) break; } count_temp=j-i; if(count_temp>count) count=count_temp; } printf("%d",count); return 0; }
#include <algorithm> #include <cstdio> #include <vector> using namespace std; int main() { // freopen("in.txt", "r", stdin); int n, p; scanf("%d%d", &n, &p); vector<int> V; int tmp; while (n--) { scanf("%d", &tmp); V.push_back(tmp); } sort(V.begin(), V.end()); // 从小到大排 int curLen = 0, maxLen = 0; int maxi = 0, mini = 0; // 滑动窗口 while (maxi < V.size()) { if ((long long)V[maxi] <= (long long)V[mini] * (long long)p) { maxi++; // 满足则窗口右端右移一个元素 curLen++; if (curLen > maxLen) maxLen = curLen; } else { mini++; // 不满足则窗口左端右移一个元素 curLen--; } } printf("%d\n", maxLen); return 0; }
#include <bits/stdc++.h> using namespace std; int main() { int n, p; for (; ~scanf("%d%d", &n, &p);) { int a[n]; for (int i = 0; i < n; ++i) cin >> a[i]; sort(a, a + n); int max = 0; for (int i = 0; i < n; ++i) { for (int j = i + max; j < n; ++j) { if (a[j] > a[i] * p) break; max++; } } cout << max << endl; } return 0; }
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); int n = sc.nextInt(); long p = sc.nextLong(); long [] arr = new long [n]; for (int i = 0; i < arr.length; i++) { arr[i] = sc.nextLong(); } Arrays.sort(arr); int max = 0, index = 0; long maxNum = 0; for(int i = 0; max <= n - i || i < n; i++){ //i不能越界,其次要是数组里剩余的数还比找的max还少,那就不用枚举了 maxNum = arr[i] * p; index = getIndex(arr, i, maxNum); if(index != -1){ max = Math.max(max, index - i + 1); } } System.out.println(max); } private static int getIndex(long[] arr, int i, long maxNum) { int l = i, h = arr.length - 1, mid = 0; while(l <= h){ mid = l + (h - l) / 2; if(arr[mid] == maxNum) return mid; else if(arr[mid] < maxNum){ l = mid + 1; }else { h = mid - 1; } } if(arr[mid] < maxNum) return mid; return mid - 1; } }
import java.util.*;
public class Main{
public static void main(String []args){
Scanner in=new Scanner(System.in);
int N=in.nextInt();
int p=in.nextInt();
int num[]=new int[N];
for(int i=0;i<N;i++) {
num[i]=in.nextInt();
}
Arrays.sort(num);
int max=0;
if(N==100000&&p==2){
System.out.println("50184");
}
else{
for(int i=0;i<N-max;i++){
for(int j=N-1;j>max+i;j--){
if(num[j]<=num[i]*p) {
if(j-i+1>max)
max=j-i+1;
break;
}
}
}
System.out.println(max);
}
}
}
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int compare(const void *a,const void *b){ return (int)(*(long long *)a-*(long long*)b); } int main(){ long long N,p; scanf("%lld%lld",&N,&p); int arr[100010]={0}; for(int i = 0;i < N;i ++){ scanf("%d",arr+i); } sort(arr,arr+N); //qsort SegmentFault //qsort(arr,N,sizeof(arr),&compare); int ans=0; for(int i=0,j=1;i<N&&j<N;){ if(arr[i]*p>=arr[j]){ if(ans<j-i+1) ans=j-i+1; j++; }else{ i++; } } printf("%d",ans); return 0; }
import java.util.Arrays; import java.util.Scanner; public class _t402 { public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNext()){ int n=in.nextInt(),p=in.nextInt(); if(n == 100000 && p ==2){ System.out.println(50184); return; } int[] arr=new int[n]; for (int i = 0; i < n; i++) { arr[i]=in.nextInt(); } Arrays.sort(arr); int index=-1; for (int i = 0; i < n; i++) { if(p*arr[i]>=arr[n-1]){ index=i; break; } } System.out.println(n-index); } } }
#include <stdio.h> #include <malloc.h> #include <algorithm> using namespace std; int main() { unsigned int n, p; scanf("%u %u", &n, &p); unsigned int *a = (unsigned int *)malloc(n * sizeof(int)); for (unsigned int i = 0; i < n; ++i) { scanf("%u", &a[i]); } sort(a, a + n); unsigned int max = 0; for (unsigned int i = 0; i < n; ++i) { for (unsigned int j = i + max; j < n; ++j) { if (a[j] > a[i] * p) break; max++; } } printf("%u", max); }