[APIO2016] Gap
Question
题意比较简单,让你在有限次查询中,找到一个严格递增的非负整数数列中的最大差值(
ai+1−ai
a
i
+
1
−
a
i
)
0≤a1<a2<...<an≤1018
0
≤
a
1
<
a
2
<
.
.
.
<
a
n
≤
10
18
查询函数
MinMax(s,t,mn,mx)
M
i
n
M
a
x
(
s
,
t
,
m
n
,
m
x
)
mn 会返回 满足
ai∈[s,t]
a
i
∈
[
s
,
t
]
中
ai
a
i
的最小值
mx 返回最大值
Solution
第一次做交互题,感觉好麻烦
子任务1
从两端开始查询,不断缩小范围,每次可以得到数列中的两个值, n/2 n / 2 次查询就能得到所有数
子任务2
考虑分块
不算最大值和最小值的话,还剩下
n−2
n
−
2
个数,如果把
[a1,an]
[
a
1
,
a
n
]
平均分成
n−1
n
−
1
个小区间的话,就会惊奇地发现,一定有至少一个小区间没有那
n−2
n
−
2
个数中的任何一个,这样的话,小区间内部就不用管了,直接看块与块之间的差就行了
M
M
最大会是
具体实现会有一些小细节,比如 如何取整啦,加一减一啦,不能越界啦。还有要注意查询时mn, mx都要用取地址符’&’
冗长代码
#include "gap.h"
#include "iostream"
#include "cstdio"
#include "cmath"
#define For(i,s,e) for(int i=(s); i<=(e); i++)
#define Rep(i,s,e) for(int i=(s); i>=(e); i--)
using namespace std;
typedef long long LL;
const LL Inf=1e18;
const int N=100000+1;
struct Node{
bool exist;
LL Max, Min;
}Block[N];
LL a[N], Last, limL, limR;
LL lstMax=Inf, lstMin=0, Max, Min, Ans=0, Len;
long long findGap(int T, int n)
{
if(T==1){
int l=1, r=n;
while(l<=r){
MinMax(lstMin, lstMax, &Min, &Max);
a[l]=Min, a[r]=Max;
l++, r--; lstMin=Min+1, lstMax=Max-1;
}
For(i,2,n) Ans=max(Ans, a[i]-a[i-1]);
} else {
MinMax(lstMin, lstMax, &limL, &limR);
Len=ceil((limR-limL-1)/(n-1.0)); lstMin=limL+1, lstMax=max(lstMin, min(limR-1, lstMin+Len-1));
For(i,1,n-1){
MinMax(lstMin, lstMax, &Min, &Max);
if(Min==-1) Block[i]=(Node){ 0, lstMin, lstMax};
else Block[i]=(Node){ 1, Max, Min};
lstMin=lstMax+1, lstMax=max(lstMin, min(limR-1, lstMin+Len-1));
}
Last=limL;
For(i,1,n-1){
if(Block[i].exist){
Ans=max(Ans, Block[i].Min-Last); Last=Block[i].Max;
} else {
Ans=max(Ans, Block[i].Max-Last);
}
}
Ans=max(Ans, limR-Last);
}
return Ans;
}