传送门
题意
交互
给定\(n\), 有一个\(1-n\)的排列, 每次你可以询问\(x\)位置的数, 询问次数不超过\(100\)
求任意一个位置k, 使得\(a_k < \min(a_{k-1}, a_{k+1})\), 我们认为\(a_0=a_{n+1}= +\infty\)
题解
非常炫酷的交互!
当你看到题目的时候, 1e5的排列, 只能询问一个数, 而非某个区间的权值~!!!
只能100次, 结果几乎没有单调性, 完全独立,那不是酷毙了!!!让人有一种十分想切得感觉
炫酷题
显然大概是要二分啥的 , 问题在于某个位置的数, 并没有单调性
没有单调性, 那我们就给他创造单调性!,.....emm创造不出来
那么是不是由于没有单调性的情况非常简单?单独解决掉没有单调性的的情况后就有单调性了?....
唉对, 如果不是特殊构造的数据, 那么一个数比相邻得数小应该很常见吧
经过这样的思考,您会开始考虑:
如果\(a_2 > a_1\) 直接输出1,\(a_{n-1} > a_n\) 直接输出n,
除此之外, a数组一开始必然下降, 最后必然上升, 那么整个数组必然如此:
显然, 每个山谷都能成为答案,也只有山谷能成为答案
这时候, 你应该想到三分, 只有一个山谷显然可以三分, 复杂度也接近
一种想当然的想法是, 直接三分必然会趋近其中一个山谷, 得到答案
事实证明: 大多数情况也是如此, 并且会得到一个wrong on test61的罚时
关于三分法本质的探究和一种解决方案
为什么会wa呢, 我们来考虑一种情况
难道是因为我们没有判断左右两边导致的?但事实上这种情况也同样会导致
所以我们的做法假了为什么会假呢?这时候我们要考虑三分法本质
对于单谷函数, 每次取两个点假如是这样
这两个点呈上升趋势, 山谷要么在两点之间, 要么在两点左边, 我们把右边界缩小到第二个点, 实质上是在定位山谷
在有多个山谷时, 这种单调性依然成立!
wa的原因实际上是因为在有多个山谷的时候, 几次三分定位的山谷不同
更准确的来说, 每次三分(见上图)实际上是定位了若干个山谷(左边黑色部分), 抛弃了一些山谷(红色部分)
仔细思考, 我们只要避免之后的定位定位到抛弃的山谷即可
运用跳跃的思维, 您会得到一种解决方案
我们记录每次询问交互库得到的最小值, 以及所在的位置
假如在某次三分中,取到两个点都大于最小值,分类讨论:
如果两个点都在最小值左边, 将左端点设成三分取的第二个点
都在右边,就把右端点设成第一个点
在两点之间, 显然中间存在山谷, 让左端点等于第一个点, 右端点等于第二个点
这样做是没有问题的, 可以保证能够定位到某个山谷, 但是为什么不会定位到被抛弃的山谷呢?
假如某一时刻是这样的
在这张图里面, 每个断点会被断开, 是因为它们右边或边必然存在一个点比他小,
如果要定位到一个被抛弃的山谷, 显然只有两个点都在下图灰色部分中
这时候两个点都会比断点大, 而记录的最小值一定小于断点, 所以, 这时候会定位到他们左边, 而非抛弃山谷
时间复杂度当然也是对的, 因为每次出现这个情况, 长度都会缩小到原来的三分之一
很妙啊
Impl
int l=1, r=n;
int minp=-1, minv=0x3f3f3f3f;
// 感谢@wzx大佬的hack, 这里不能将初始值设为n, 要设为正无穷
while(l < r){
int mid = (r-l+1)/3;
int lmid=min(r, l+mid), rmid=max(l, r-mid);
if(lmid > rmid) swap(lmid, rmid);
if(lmid == rmid){
if(lmid > l) lmid--;
else rmid++;
}
int lans=get(lmid), rans=get(rmid);
if(min(lans, rans) > minv){
if(rmid < minp){
l = rmid+1;
}else if(lmid > minp){
r = lmid-1;
}else{
l=lmid+1, r=rmid-1;
}
}else {
if(lans < rans) minv=lans, minp=lmid;
else minv=rans, minp=rmid;
}
if(lans < rans) r = rmid-1;
else l = lmid+1;
}
pri(l);