PAT成长之路——1030 完美数列 (25 分)

版权声明:有善始者实繁,能克终者盖寡。 https://blog.csdn.net/weixin_43987810/article/details/86765990

题目:

1030 完美数列 (25 分)

给定一个正整数数列,和正整数 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

分析:

先使用排序,使得数组内元素为从小到大。

另外注意一点就是找到一对max和min,其间所有的元素都包含在长度以内,即完美数列的每个元素都在【min, max】以内。

最后注意比较的时候牵扯乘法,不声明long long的话会导致溢出(不要只看到题目给定的范围在int范围内,程序中还可能对其做乘法等运算)。

做法1:长度递减遍历每个拥有此长度的数组,看其是否完美。比如说:开始的时候len = N, 因此只需判断最大的数组即可;之后len = N - 1, 此时看a2-aN这个数组和 a1-a(N - 1)这个数组,以此类推。(超时)

做法2:min从最小值开始遍历,每次固定min,看数组最大长度;如果后一个数组的长度比该数组的长,len = 后一个数组长度。

代码:

做法一代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    long long v[100010];
    int N, p;
    int i, j;
    int k, l;
    int last;

    cin >> N >> p;
    for(i = 0; i < N; i++)
        scanf("%lld", &v[i]);
    sort(v, v + N);
    for(last = N - 1; last >= 0; last--)
        for(i = 0, j = last; j <= N - 1; i++, j++)//两重循环导致超时
            if(v[j] <= v[i] * p)
            {
                cout << last + 1 << endl;
                return 0;
            }
    return 0;
}

做法二代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
long long v[100010];

int main()
{
    int N, p;
    int i, j;
    int len = 0;

    cin >> N >> p;
    for(i = 0; i < N; i++)
        scanf("%lld", &v[i]);
    sort(v, v + N);
    for(i = 0; i < N; i++)
    {
        if(i + len < N && v[i + len] <= v[i] * p)//此处判断避免超时
        {
            for(j = i + len + 1; j <= N - 1; j++)
                if(v[j] > v[i] * p)
                    break;
            len = j - i;
        }
    }
    cout << len << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43987810/article/details/86765990