1. 程式人生 > 實用技巧 >P5682 [CSPJX2019]次大值【民間資料】

P5682 [CSPJX2019]次大值【民間資料】

題目描述

Alice 有 nnn 個正整數,數字從 1∼n1 \sim n1n 編號,分別為 a1,a2,…,ana_1,a_2, \dots , a_na1,a2,,an
Bob 剛學習取模運算,於是便拿這 nnn 個數進行練習,他寫下了所有

ai mod aj(1≤i,j≤n∧i≠j)a_i \bmod a_j (1 \le i,j \le n \wedge i \neq j) aimodaj(1i,jni=j)

的值,其中  mod \bmodmod 表示取模運算。

Alice 想知道所有的結果中,嚴格次大值是多少。將取模後得到的所有值進行去重,即相同的結果數值只保留一個,剩餘數中第二大的值就稱為嚴格次大值。

輸入格式

第一行一個正整數 nnn,表示數字個數。
第二行 nnn 個正整數表示 aia_iai

輸出格式

僅一行一個整數表示答案。
若若取模結果去重後剩餘數字不足兩個,則輸出 −1-11。

輸入輸出樣例

輸入 #1
4
4 5 5 6
輸出 #1
4
輸入 #2
4
1 1 1 1
輸出 #2
-1
輸入 #3
7
12 3 8 5 7 20 15
輸出 #3
12

說明/提示

【資料範圍】
對於 40%40\%40% 的資料,1≤n,ai≤1001\le n,a_i \le 1001n,ai100;
對於 70%70\%70% 的資料,1≤n≤30001\le n \le 30001n3000,1≤ai≤1051\le a_i \le 10^51ai105;
對於 100%100\%100% 的資料,3≤n≤2×1053 \le n \le 2\times 10^53n2×105,1≤ai≤1091\le a_i \le 10^91ai109。

【樣例 111 解釋】
所有取模的結果為 {4,4,4,1,0,5,1,0,5,2,1,1}\{4,4,4,1,0,5,1,0,5,2,1,1\}{4,4,4,1,0,5,1,0,5,2,1,1}。
去重後有:{0,1,2,4,5}\{0,1,2,4,5 \}{0,1,2,4,5},結果為 444。

根據題意要求,最後我們是要進行去重操作的,所以不管在哪裡去重都是可以的,所以我們先對於讀入資料進行去重,然後從小到大排序,因為我們知道,每個元素都需要和除他之外的所有元素進行比較,所以我們這樣的操作其實對於我們最後的操作是沒有影響的;

然後,轉折點來了qwq

到這一步其實正解是一種非常簡單的做法,但是由於本人過於蒟蒻,所以我的方法是兩層迴圈,為了降低複雜度,我們發現,從小到大對元素進行排序之後,如果a%b中b的值大於a,那麼就是說之後所有元素的值都大於a,所以a%他們其實結果就是a,依據這樣的方法,我開心的把程式碼敲了出來,開心的交了上去,然後開心的發現自己最後三個點T了qwq

也就是說上面這種方法雖然在一定程度上降低了時間複雜度,但是對於某些特殊資料,它的複雜度還是太高的,所以我們來想另外的方法

其實在第一種方法中我們就可以發現,有由於所有元素都是從小到大排序的,所以除了最後一個元素之外,每一個元素取餘的最大值就是他自己,所以嚴格次大值其實就是倒數第三個數的值,but,題目中還有一個坑點在於他沒有規定i j的比較順序,也就是說,可以用大數%小數,這樣的話得到的數一定比大數小,按照常理來說,這種情況可以很容易被排除,但是不要忘了我們還有最後一個個元素呢!我們不知道最後一個元素%倒數第二個元素的值與倒數第三個元素的值到底誰大誰小,所以應該再取一次MAX才對

70分程式碼(本人第一遍寫的qwq)

#include<bits/stdc++.h>
using namespace std;

int n;
int vis[5020000];
int num=0;
int ans[5020000];
int a[5020000];

int main() {
    cin>>n;
    for(int i=1; i<=n; i++) {
        int x;
        cin>>x;
        if(!vis[x]) {
            num++;
            vis[x]=1;
            a[num]=x;
        }
    }
    sort(a+1,a+num+1);// small

    int c=0;
    for(int i=1; i<=num; i++) {
        bool flag=0;
        for(int j=1; j<=num; j++) {
            if(a[i]==a[j]) continue;
            if(a[i]>a[j]&&flag==1) break;
            c++;
            ans[c]=a[i]%a[j];
        }
    }
    num=0;
    int b[502000];
    memset(vis,0,sizeof(vis));
    sort(ans+1,ans+1+c);
    for(int i=1; i<=c; i++) {
        int x=ans[i];
        if(!vis[ans[i]]) {
            num++;
            vis[ans[i]]=1;
            b[num]=ans[i];
        }
    }
    sort(b+1,b+1+num);
    if(num==0) cout<<-1<<endl;
    else cout<<b[num-1]<<endl;
    return 0;
}

正解(AC程式碼):

#include<bits/stdc++.h>
using namespace std;

int n;
int vis[5020000];
int num=0;
int ans[5020000];
int a[5020000];
int b[5020000];
int main() {
    cin>>n;
    for(int i=1; i<=n; i++) {
            int x;
            cin>>x;
            if(!vis[x]) {
                num++;
                vis[x]=1;
                a[num]=x;
            }
        }
        sort(a+1,a+num+1);// small
        if(num>=3) cout<<max(a[num-2],a[num]%a[num-1])<<endl;
        else cout<<-1<<endl;
        return 0;
}

完結撒花✿✿ヽ(°▽°)ノ✿

根據題意要求,最後我們是要進行去重操作的,所以不管在哪裡去重都是可以的,所以我們先對於讀入資料進行去重,然後從小到大排序,因為我們知道,每個元素都需要和除他之外的所有元素進行比較,所以我們這樣的操作其實對於