APIO2016 Gap [交互题]

[APIO2016] Gap

Question

题意比较简单,让你在有限次查询中,找到一个严格递增的非负整数数列中的最大差值( ai+1ai a i + 1 − a i ) 0a1<a2<...<an1018 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

考虑分块
不算最大值和最小值的话,还剩下 n2 n − 2 个数,如果把 [a1,an] [ a 1 , a n ] 平均分成 n1 n − 1 个小区间的话,就会惊奇地发现,一定有至少一个小区间没有那 n2 n − 2 个数中的任何一个,这样的话,小区间内部就不用管了,直接看块与块之间的差就行了
M M 最大会是1+n+n1+n2=3n2
具体实现会有一些小细节,比如 如何取整啦,加一减一啦,不能越界啦。还有要注意查询时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;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值