【全网最细PAT题解】【PAT乙】1030 完美数列(测试点4、测试点5)

70 篇文章 0 订阅
文章描述了一个关于完美数列的编程问题,要求在给定的正整数集合中找到能构成完美数列的最大数量。解决方案是通过对数列排序,使用双重循环并进行剪枝优化以降低时间复杂度,确保算法能在限制时间内运行。关键在于理解题目允许选择任意子集而非连续序列,并注意数据类型防止溢出。
摘要由CSDN通过智能技术生成

题目链接

1030 完美数列

题目描述

给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列。

现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。

输入格式:
输入第一行给出两个正整数 N 和 p,其中 N(≤10 
5
 )是输入的正整数的个数,p(≤10 
9
 )是给定的参数。第二行给出 N 个正整数,每个数不超过 10 
9
 。

输出格式:
在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。

输入样例:
10 8
2 3 20 4 5 1 6 7 8 9
输出样例:
8

题目大意

不好概括,还是看题吧

解题思路

本题乍一看很唬人,像是一个动态规划或者贪心算法,但是只要好好读题就回发现,题目要求的是你从中选择尽可能多的数构成一个完美数列而不是按照题目中所给的顺序选择一个完美数列,这样我们就可以将给出的一组数按照从小到大排序后用双重循环来暴力解决
但是需要注意的是,本题的暴力虽说可以,但是对时间要求非常苛刻,必须完美的剪枝才能通过测试点4

  • 测试点4的问题是完美剪枝,不仅内层循环要从上一次最长的地方开始循环,一不满足条件内层循环也必须直接break,否则会出现时间超限
  • 测试点五的错误原因是用int类型会导致超限因为给出的范围虽然是10^9,但是由于要判断Mn*p的关系,两个数相乘就回超出int的范围
    具体的解题思路可以看下面题解的注释

题解

#include<bits/stdc++.h>
using namespace std;
vector<long long> v;
//这里是测地点5错误原因,包括下面的p也不能用int ,
// 因为给出的范围虽然是10^9,但是由于要判断M与n*p的关系,两个数相乘就回超出int的范围
int main(){
    int n;
    long long p;
    //注意long long
    cin>>n>>p;
    v.resize(n);
    for(int i=0;i<n;i++)    cin>>v[i];
    sort(v.begin(),v.end());
    //因为题目中只是说从给出的数列中选出若干数字,并没有说必须按照给出的数列连续选出,所以可以排序后再判断
    int mmax=0;
    //用于记录当前最长的数组有几个元素,可以在内部循环中减少循环次数,降低时间复杂度
    for(int i=0;i<v.size();i++){
        for(int j=i+mmax;j<v.size();j++){
        //这里直接从最大长度开始判断,可以降低不少次的循环次数
            if(v[i]*p>=v[j]){
                //这里的相乘就是测试点5超限答案错误的原因
                mmax=j-i+1;
            }
            else    break;
            //这里不满足说明后面的循环都不满足了(因为前面已经将数列从小到大排好序了,后面只可能会更不满足题目条件)
            //也需要跳出循环,本题时间复杂度卡的非常紧,暴力方法不剪枝也会超限
        }
    }
    cout<<mmax;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值