PAT B1030/A1085 完美数列 (25point(s))

题目链接
本题我自己先想了一种方法,先将原数组递增排列,完美数列必然是由递增数列中间连续的元素组成,用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;
}
发布了81 篇原创文章 · 获赞 0 · 访问量 671

猜你喜欢

转载自blog.csdn.net/weixin_44546393/article/details/105372285