洛谷 P3957 跳房子 二分+DP检验+单调队列优化
题意:有n个格子,第i个格子距离起点xi得分si,有一个机器人只能跳d的距离,花1金币可以增加1灵活度,问要得到k分至少需要多少金币
1 ≤ n ≤ 5e5, 1 ≤ d ≤2000, 1 ≤ xi, k ≤ 1e9, |si| < 1e5
思路:花多少金币的决策有单调性,所以先二分答案,用dp检验,设dp[i]表示在第i个格子获得的最大分数
容易看出dp[i] = max(dp[k])+s[i],k能走到i,显然不优化是n^2的复杂度
但也比较显然这就是单调队列优化的模型(P1725),于是nlogn AC
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<queue> 6 #define INF 0x3f3f3f3f 7 #define LL long long 8 #define debug(x) cout << "[" << x << "]" << endl 9 using namespace std; 10 11 const int mx = 5e5+10; 12 int x[mx], s[mx]; 13 LL dp[mx]; 14 int n, k, d; 15 16 bool check(int g){ 17 deque<int> q; 18 int p = 0, l = max(1, d-g), r = d+g; 19 for (int i = 1; i <= n; i++){ 20 dp[i] = -INF; 21 while (x[i]-x[p] >= l && p < i){ 22 while (!q.empty() && dp[p] >= dp[q.back()]) q.pop_back(); 23 q.push_back(p++); 24 } 25 while (!q.empty() && x[i]-x[q.front()] > r) q.pop_front(); 26 if (q.empty() || dp[q.front()] == -INF) continue; 27 dp[i] = dp[q.front()]+s[i]; 28 if (dp[i] >= k) return 1; 29 } 30 return 0; 31 } 32 33 int main(){ 34 scanf("%d%d%d", &n, &d, &k); 35 for (int i = 1; i <= n; i++) 36 scanf("%d%d", &x[i], &s[i]); 37 int l = 0, r = 2e9, ans = -1; 38 while (l <= r){ 39 int mid = l+(r-l)/2; 40 if (check(mid)) { 41 ans = mid; 42 r = mid-1; 43 } 44 else l = mid+1; 45 } 46 printf("%d\n", ans); 47 return 0; 48 }