P5682 [CSPJX2019]次大值【民間資料】
題目描述
Alice 有 nnn 個正整數,數字從 1∼n1 \sim n1∼n 編號,分別為 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(1≤i,j≤n∧i=j)
的值,其中 mod \bmodmod 表示取模運算。
Alice 想知道所有的結果中,嚴格次大值是多少。將取模後得到的所有值進行去重,即相同的結果數值只保留一個,剩餘數中第二大的值就稱為嚴格次大值。
輸入格式
第一行一個正整數 nnn,表示數字個數。
第二行 nnn 個正整數表示 aia_iai。
輸出格式
僅一行一個整數表示答案。
若若取模結果去重後剩餘數字不足兩個,則輸出 −1-1−1。
輸入輸出樣例
輸入 #14 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 1001≤n,ai≤100;
對於 70%70\%70% 的資料,1≤n≤30001\le n \le 30001≤n≤3000,1≤ai≤1051\le a_i \le 10^51≤ai≤105;
對於 100%100\%100% 的資料,3≤n≤2×1053 \le n \le 2\times 10^53≤n≤2×105,1≤ai≤1091\le a_i \le 10^91≤ai≤109。
【樣例 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; }
完結撒花✿✿ヽ(°▽°)ノ✿
根據題意要求,最後我們是要進行去重操作的,所以不管在哪裡去重都是可以的,所以我們先對於讀入資料進行去重,然後從小到大排序,因為我們知道,每個元素都需要和除他之外的所有元素進行比較,所以我們這樣的操作其實對於