【UOJ #206】【APIO2016】Gap

本文介绍了一种算法,用于在给定的递增数列中找到连续两项之间的最大差距。通过对序列进行二分查找和使用MinMax函数,文章提出了两种解决方案,分别针对不同的得分标准。一种方法适用于较小的调用次数限制,而另一种则能在更宽松的限制下获得更高的分数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

有 N 个严格递增的非负整数a1,a2,…,aN(0≤a1&lt;a2&lt;⋯&lt;aN≤1018)a_1,a_2,…,a_N(0≤a_1&lt;a_2&lt;⋯&lt;a_N≤10^{18})a1,a2,,aN0a1<a2<<aN1018)。你需要找出 ai+1−ai(0≤i≤N−1)a_{i+1}−a_i(0≤i≤N−1)ai+1ai0iN1里的最大的值。

你的程序不能直接读入这个整数序列,但是你可以通过给定的函数来查询该序列的信息。
定义函数MinMax(s,t,&amp;mn,&amp;mx)MinMax(s, t, \&amp; mn, \&amp; mx)MinMax(s,t,&mn,&mx),返回时,变量 mn 将会存储满足 ai∈[s,t]a_i∈[s,t]ai[s,t] 中 ai 的最小值,变量 mx 将会存储满足 ai∈[s,t]a_i∈[s,t]ai[s,t] ,ai 的最大值。

计分方式

对于所有的测试点,有 2≤N≤100000。

每一个测试点开始测试之前,M 都将被初始化为 0。

子任务 1(30 分):每一次调用 MinMax 都将使 M 加 1。为了获得所有分数,需要满足对于该子任务下的所有测试点,都有 M≤N+12M\leq \frac{N+1}{2}M2N+1

子任务 2(70 分):定义 k 为调用 MinMax 时,区间 [s,t][s,t][s,t]中的序列中数的数量。每次调用 MinMax,将使 M加上 k+1k+1k+1。如果 M≤3NM≤3NM3N,你将得到 70 分

Solution

对于30分:
显然的,你可以先找出全局的最大值和最小值,再向中间推进来找出a中全部元素,

对于70分:
我们可以先求出答案的下界为:mx−min−1\frac{mx-mi}{n-1}n1mxmi
我们考虑这个答案什么情况下会更新,找出mi,mx后,我们先把mi~mx这段值域分成n-1段,如果存在更优的答案,那么这个答案在值域上一定是跨区间的,
所以我们暴力找出每个值域区间中是否有数,有数的话mi,mx又分别是多少即可,

总的K刚好等于3N。

Code

#include "gap.h"
#include <cstdio>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=100500;
const LL INF=1e18;
int read(int &n)
{
	char ch=' ';int q=0,w=1;
	for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
	if(ch=='-')w=-1,ch=getchar();
	for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n;
LL ans;
LL doit1()
{
	LL r,l;
	MinMax(0,INF,&l,&r);
	for(int i=2;i<n;i+=2)
	{
		LL mx,mi;
		MinMax(l+1,r-1,&mi,&mx);
		ans=max(ans,max(mi-l,r-mx));
		l=mi,r=mx;
	}
	return ans=max(ans,r-l);
}
LL doit2()
{
	LL mi,mx,m,fr;
	MinMax(0,INF,&fr,&m);
	LL la=fr;
	ans=(m-fr)/(n-1);
	for(LL i=fr,t;i<m;i=la+t,la=mx)
	{
		t=ans+1;
		for(;i+1>t+la;t<<=1);
		for(MinMax(i+1LL,la+t,&mi,&mx);mi==-1;t<<=1,MinMax(i+1LL,la+t,&mi,&mx));
		ans=max(ans,mi-la);
	}
	return ans;
}
LL findGap(int T, int n1)
{
	if(n1==2)
	{
		LL mi,mx;
		MinMax(0,INF,&mi,&mx);
		return mx-mi;
	}
	n=n1;ans=0;
	return (T==1)?doit1():doit2();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值