思路:
首先發現單調性,靈活性增加 \(x+1\) 的答案肯定不會比增加 \(x\) 的答案更劣。
那麼可以二分求 \(g\),則機器人每次可以移動 \([\max(d-mid,1),d+mid]\) 這個區間內的距離,為了方便,設為 \([l,r]\)。
考慮動態規劃求得能走到的最大分數,令 \(dp_i\) 表示走到第 \(i\) 個格子的最大分數,則狀態轉移方程為:
\[dp_i = s_i + \max\limits_{j=0}^{i-1} [x_i - r \le x_j] [x_j \le x_i - l] dp_j
\]
可以使用單調佇列維護:
-
若當前隊尾為 \(j\),且 \(x_j < x_i - r\),則這個 \(j\) 無法對 \(dp_i\) 造成貢獻,直接不斷彈出即可。
-
若當前隊頭為 \(j\),且 \(x_{j+1} \le x_i - l\),則這個 \(j+1\) 可以對 \(dp_i\) 造成貢獻,不斷插入即可。
-
因為要維護最大值,可以使用單調佇列。
時間複雜度為 \(O(N \log W)\)。
完整程式碼:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const ll N=5e5+10;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
ll n,d,k,l,r,head,tail,ans=-1;
ll a[N],b[N],dp[N],Q[N];
ll check(ll l,ll r){
head=1,tail=0;
ll sum=0,x=1,y=0;
for(int i=1;i<=n+1;i++){
if(i>1)
dp[i]=-1e18;
while(a[y+1]<=a[i]-l&&y<=n){
y++;
while(dp[y]>dp[Q[tail]]&&tail>=head)
tail--;
if(dp[y]>=-1e18)
Q[++tail]=y;
}
while(a[x]<a[i]-r&&x<=n){
if(Q[head]==x)
head++;
x++;
}
if(tail>=head)
dp[i]=b[i]+dp[Q[head]];
sum=max(sum,dp[i]);
}
return sum;
}
bool End;
int main(){
// open("A.in","A.out");
n=read(),d=read(),k=read();
for(int i=1;i<=n;i++){
a[i+1]=read();
b[i+1]=read();
}
l=0,r=1e9;
while(l<=r){
ll mid=(l+r)>>1;
if(check(max(d-mid,1ll),d+mid)>=k){
r=mid-1;
ans=mid;
}
else
l=mid+1;
}
write(ans);
cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB";
return 0;
}