PAT-B 1030. 完美數列(25)

傳送門

https://pintia.cn/problem-sets/994805260223102976/problems/994805291311284224

題目

給定一個正整數數列,和正整數p,設這個數列中的最大值是M,最小值是m,如果M <= m * p,則稱這個數列是完美數列。
現在給定參數p和一些正整數,請你從中選擇盡可能多的數構成一個完美數列。
輸入格式:
輸入第一行給出兩個正整數N和p,其中N(<= 105)是輸入的正整數的個數,p(<= 109)是給定的參數。第二行給出N個正整數,每個數不超過109。
輸出格式:
在一行中輸出最多可以選擇多少個數可以用它們組成一個完美數列。
輸入樣例:
10 8
2 3 20 4 5 1 6 7 8 9
輸出樣例:
8

分析

1.首先將數字都讀進數組里,然后用sort或者qsort排序(升序),都可以
2.接著就是比較繞的一個地方了,這里我的第一種方法的時間復雜度是m * n,然后有一個測試點超時了,考慮了一下是算法太麻煩。

這里給大家介紹一種很快速的算法,以本題樣例為例:
對其排序后,是這樣的:

下標:|00|01|02|03|04|05|06|07|08|09|
數值:|01|02|03|04|05|06|07|08|09|20|

1.首先用1 * 8 = 8,然后會對比到下標為7 的位置,并記長度為8。
2.接著就厲害了,按我之前的做法是從下標為01的地方對比,這樣就麻煩了。
快速的做法是計算2 * 8 = 16,然后用下標為08的地方與其對比,發現符合,然后求出從下標01到08位置的長度,是8,不大于之前的長度,接著向后對比;用下標為09的數值與2 * 8 = 16對比,發現不符合規則,然后此次對比過程結束。
3.新的最大值是3 * 8 = 24,用下標為09的地方與其對比,發現符合,然后求從下標02到09的長度,是8,不大于之前的長度,并且發現已經全部對比完畢,所以結束。

源代碼

//C/C++實現
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(){
    int n;
    long long p;
    scanf("%d %d", &n, &p);
    vector<int> v(n);
    for(int i = 0; i < n; ++i){
        scanf("%d", &v[i]);
    }
    sort(v.begin(), v.end());
    int final_count = 0;
    for(int i = 0; i < n; ++i){
        long long max = v[i] * p;
        for(int j = i + final_count; j < n; ++j){
            if(v[j] <= max){
                if(j - i + 1 > final_count){
                    final_count = j - i + 1; //從j到i的數值的數量
                }
            }
            else{
                break;
            }
        }
    }
    printf("%d\n", final_count);
    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容