1020完美数列解题方式

题目

给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列。
 
 
 
 现在给定参数p和一些正整数,请你从中选择尽可能多的数构成一个完美数列。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

bool cmp(int a, int b) {
    return a < b;
}

void func(int a[], int n, int p) {
    int num = 0;
    for (int i = 0; i < n; i++) {
        long m = p * a[i];
        int n1 = 0;
        for (int j = i; j < n; j++) {
            if (a[j] <= m) {
                n1++;
            }
        }
        if (cmp(num, n1))num = n1;
    }
    printf("%d", num);
}

int main() {
    // freopen("in.in", "r", stdin);
    int n, p;

    scanf("%d %d", &n, &p);
    int a[n];
    for (int i = 0; i < n; i++) {
        scanf("%d",a+i);
    }
    sort(a, a + n, cmp);
    func(a, n, p);
    return 0;
}

这题思路如果按照以上的解题方式简单,时间复杂度就是O(n^2)。

对于数组输入的方式,如果将scanf输入换成cin的输入方式,可能会出现超时的情况。这里放的解法是我想到的比较容易实现的。关于其他解法,我想到二分查找的方法,但是没有实现,卡在了中间数a[mid]和m*p那里,不知道怎么判断。

参考以下的文章,low返回的就是能够到达的最大数列中不超过m*p的数字的下表。这个也需要分析才能理解,对于题目使用的二分查找的方法时间复杂度为O(nlogn)

二分查找解题思路

参考文件的多种解法出处PAT-Basic 完美数列(25) 二分法和双指针c++解题思路_牛客网 (nowcoder.com)

/*
 * 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;
}

二分查找扩展

基于二分查找,可以进一步扩展两个方法。

  • 查找第一个大于或等于x的元素位置

  • 查找第一个大于x的元素位置

文章里面还有一种双指针方法解题思路:

双指针解题:

/*
 * 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;
}

测试用例不过的情况

1.没有看来到数组的长度全部符合完美数组的情况,在输出的时候可能出现完美数组总数为0的情况,需要考虑代码的计算总数的(第一个测试点和第四个测试点)

2.使用的整型类型小于m*p的大小,造成m*p的值不准确,比较大小出错,建议使用longlong类型

数列使用longlong类型适合比较。(第5测试点)

3.我实现的第一个代码在牛客网能够通过,但是在pat官网刷题的时候发现不行,出现了超时的情况,改进的代码不会出现超时,原理和上面我写的双指针的解决方式是一样的。但是这个我在看“区间贪心”的解决方式时候突然想起来这个可以当初由  a[i]<=完美数列<=mp=a[i]*p  来组成的区间来解决

改进代码:

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

int main(){
	freopen("in.txt","r",stdin);
	int n,p;
	scanf("%d %d",&n,&p);
	
	long long a[n];//longlong
	for(int i=0;i<n;i++){
		scanf("%lld",a+i);//输入格式为lld
	}
	int sum=0,k=0;
	sort(a,a+n);
	for(int i=0;i<n;i++){
		int num=k-i;
		long long mp=a[i]*p;
		for(;k<n;k++){
			if(a[k]>mp){
				break;
			}
			num++;
		}
		sum=sum>num?sum:num;
	}
	printf("%d",sum); 
	
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值