【UOJ #206】【APIO2016】Gap

Description

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

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

计分方式

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

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

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

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

Solution

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

对于70分:
我们可以先求出答案的下界为: m x − m i n − 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();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值