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;
}

 

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

 

 

根据题意要求,最后我们是要进行去重操作的,所以不管在哪里去重都是可以的,所以我们先对于读入数据进行去重,然后从小到大排序,因为我们知道,每个元素都需要和除他之外的所有元素进行比较,所以我们这样的操作其实对于

posted @ 2020-11-28 20:22  yxr~  阅读(321)  评论(0编辑  收藏  举报