题目链接
本题我自己先想了一种方法,先将原数组递增排列,完美数列必然是由递增数列中间连续的元素组成,用left指向递增数列最左,right指向递增数列最右,不满足条件时right减或者left增,不断试图直至满足条件为止。代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
int a[100010];
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 left=0,right=n-1;
while(left<right){
if(a[right]<=(long long)a[left]*p) break;//满足条件,直接跳出a[right]
else{//不满足条件
if(a[right]<=(long long)a[left+1]*p){
left++;//可能将left+1会使条件满足
break;
}
if(a[right-1]<=(long long)a[left]*p){
//可能将right-1会使条件满足
right--;
break;
}//试探均无效,只能right和left均移动
left++;
right--;
}
}
printf("%d",right-left+1);//输出长度
return 0;
}
这个解法只能拿23分,原因在于left和right的移动距离之差不会超过1,移动总是对称的。考虑特殊情形,如数组{1,2,5,6,7},p=2。按上述算法得到的完美数组是{5,6},但实际的完美数组却是{5,6,7}。
故想到一种更好的方法,要用到upper_bound的算法。AC代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
int a[100010];
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 ans=1;//最大长度,初值为1(完美数列至少有一个数)
for(int i=0;i<n;i++){
//在a[i+1]~a[n]中查找第一个“超过”a[i]*p的数,并将其下标给j(说明a[i]~a[j-1]是完美数组)
int j=upper_bound(a+i+1,a+n,(long long)a[i]*p)-a;
ans=max(ans,j-i);//更新最大长度
}
printf("%d",ans);
return 0;
}