洛谷 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且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 }

猜你喜欢

转载自www.cnblogs.com/QAQorz/p/9759764.html