题目描述
Alice 有 n 个正整数,数字从 1∼n 编号,分别为 a1,a2,…,an。
Bob 刚学习取模运算,于是便拿这 n 个数进行练习,他写下了所有
a[i] mod a[j](1≤i,j≤∧i≠j)
的值,其中 mod 表示取模运算。
Alice 想知道所有的结果中,严格次大值是多少。将取模后得到的所有值进行去重,即相同的结果数值只保留一个,剩余数中第二大的值就称为严格次大值。
输入格式
第一行一个正整数 n,表示数字个数。
第二行 n 个正整数表示 ai。
输出格式
仅一行一个整数表示答案。
若取模结果去重后剩余数字不足两个,则输出 −1。
输入输出样例
输入 #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% 的数据,1≤n,ai≤100;
对于 70% 的数据,1≤n≤3000,1≤ai≤10^5;
对于 100% 的数据,3≤n≤2×10^5,1≤ai≤10^9。
【样例 11 解释】
所有取模的结果为 {4,4,4,1,0,5,1,0,5,2,1,1}。
去重后有:{0,1,2,4,5},结果为 4。
===============================我是分割线==================================
做这道题的时候我一直在想:凭啥这道题是普及/提高-感觉像普及-的题目。
对了做个题目传送门。
好的来看题目。
题目中重点就是求a数组任意选两个不同的数字取模之后的严格次大值。
看到数据n<=2*10^5,可以知道暴力模拟会TLE,所以,考虑数学做法,时间复杂度控制在O(nlogn)左右。
在所有数mod完之后,最大值一定是原本a数组里面的严格次大值,很简单,严格次大值mod完最大值之后仍然不变,比它小那么mod完之后比它还小,比它大(最大值)mod完之后变成0,所以最大值找到,该找严格次大值了。
本蒟蒻认为原数组里面的第三大值就是mod完之后的严格次大值了,于是提交上了以下代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int N=1e6+10;
int maxx1,maxx2;
int a[N],n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);
maxx1=a[n];
while(a[n]==maxx1) n--;
maxx1=a[n];
for(int i=n;i>=1;i--){
if(a[i]!=maxx1) maxx2=a[i];
if(maxx2!=0) break;
}
if(maxx1==0||maxx2==0) printf("-1");
else printf("%d",maxx2);
return 0;
}
结果是样例全过,题目WA了一个点。
我把那个WA的点下载了下来,发现这个程序在输入为:
3
9 5 3
的时候WA了。
明显,按照该程序的思路,找到了原数组中去重后的第三大值,但是9 mod 5=4,4>3,5>4,所以严格次大值应该是4而不是程序输出的3。
所以应该特判这种情况,对原数组的最大值向次大值取模,如果要比原数组第三大值要大,那么将次大值更改为最大值 mod 次大值。(这些操作都是去重之后的)
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const int N=1e6+10;
int maxx1,maxx2;//maxx1是最大值,maxx2是严格次大值
int a[N],n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);//排序
int nn=n;//存n,后面会改变
maxx1=a[n];//先把maxx1当作临时变量
while(a[n]==maxx1&&n>0) n--;//对最大值进行一个相当于删除的操作
maxx1=a[n];//存入数组中的严格次大值
for(int i=n;i>=1;i--){//找去重之后的第三大值
if(a[i]!=maxx1) maxx2=a[i];
if(maxx2!=0) break;
}
if(a[nn]%maxx1>maxx2) maxx2=a[nn]%maxx1;//样例1特殊情况判断
if(maxx1==0||maxx2==0) printf("-1");//无解
else printf("%d",maxx2);//输出
return 0;
}
注意:这道题数据不算很强。
最后问一下,大家认为这道题应该算什么难度呢?