給出\(n\)個指針的座標\(h_i\),以及\(m\)個地址的座標\(p_i\),每一秒指針均可以移動一個單位,求最少的時間使得全部地址都被遍歷ios
\(1 \le n,m \le 10^5,1 \le h_i,p_i \le 10^{10}\)c++
老實說我當時搞不出來,看了tutorial以爲方法很不錯spa
首先你們都知道的是排序(已省略)並二分答案\(mid\),指針
而後從左到右考慮每個地址被覆蓋的狀況(重要)code
咱們指望枚舉過程當中作到的是排序
對於條件1,顯然當該地址存在相對於它的左右邊都有指針且可被覆蓋時,優先選左端ci
對於條件2且只剩下右端點能夠選擇時,找能用的最靠近它的端點,這個時候有兩種作法it
依此列出式子而後比較一下選擇最優的策略(踩點包含了右端點沒法擴展的極端狀況)io
寫起來特簡潔,這道題真是喵啊喵啊class
#include<bits/stdc++.h> using namespace std; using ll = long long; const int MAXN = 1e5+11; int n,m; ll p[MAXN],h[MAXN]; bool C(ll mid){ int i=1,j=1; while(j<=m){ while(h[i]+mid<p[j]&&i<=n) i++; if(i>n) return 0; if(h[i]<=p[j]){ while(h[i]+mid>=p[j]&&j<=m) j++; i++; }else if(mid>=h[i]-p[j]){ ll t=max(mid-2ll*(h[i]-p[j]),(mid-(h[i]-p[j]))/2)+h[i]; while(t>=p[j]&&j<=m) j++; i++; }else return 0; } return 1; } int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); while(cin>>n>>m){ for(int i=1;i<=n;i++) cin>>h[i]; for(int i=1;i<=m;i++) cin>>p[i]; ll lo=0,hi=2e10; while(lo<hi){ ll mid=lo+(hi-lo)/2; if(C(mid)) hi=mid; else lo=mid+1; } cout<<lo<<endl; } return 0; }