P5682 [CSP-J2019 江西] 次大值

题目描述

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

注意:这道题数据不算很强。

最后问一下,大家认为这道题应该算什么难度呢?

  • 17
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值