【UOJ #206】【APIO2016】Gap
阿新 • • 發佈:2018-12-07
Description
有 N 個嚴格遞增的非負整數 。你需要找出 裡的最大的值。
你的程式不能直接讀入這個整數序列,但是你可以通過給定的函式來查詢該序列的資訊。
定義函式
,返回時,變數 mn 將會儲存滿足
中 ai 的最小值,變數 mx 將會儲存滿足
,ai 的最大值。
計分方式
對於所有的測試點,有 2≤N≤100000。
每一個測試點開始測試之前,M 都將被初始化為 0。
子任務 1(30 分):每一次呼叫 MinMax 都將使 M 加 1。為了獲得所有分數,需要滿足對於該子任務下的所有測試點,都有 。
子任務 2(70 分):定義 k 為呼叫 MinMax 時,區間 中的序列中數的數量。每次呼叫 MinMax,將使 M加上 。如果 ,你將得到 70 分
Solution
對於30分:
顯然的,你可以先找出全域性的最大值和最小值,再向中間推進來找出a中全部元素,
對於70分:
我們可以先求出答案的下界為:
我們考慮這個答案什麼情況下會更新,找出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();
}