洛谷 P3089 DP+单调队列

题意:n个点,点i的坐标为xi得分为ai,开始可以站在任意一个点上往一个方向跳,每次跳的距离不能少于上一次,问最大的得分

n <= 1000

思路:设dp[i][j]为从j到i得到的最大得分,dp[i][j] = max(dp[j][k]) + a[i]

先枚举j再枚举i,可以发现k有单调性,能用单调队列的思想维护max(dp[j][k])

然后正着做一遍再倒着做一遍就行

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #define LL long long
 6 #define debug(x) cout << "[" << x << "]" << endl
 7 using namespace std;
 8 
 9 const int mx = 1010;
10 struct node{
11     int x, v;
12     bool operator < (const node& a) const{
13         return x < a.x;
14     }
15 }a[mx];
16 
17 int dp[mx][mx];
18 
19 int main(){
20     int n, ans = 0;
21     scanf("%d", &n);
22     for (int i = 1; i <= n; i++)
23         scanf("%d%d", &a[i].x, &a[i].v);
24     sort(a+1, a+n+1);
25     for (int j = 1; j <= n; j++){
26         int k = j-1, v = a[j].v;
27         for (int i = j+1; i <= n; i++){
28             while (k && a[i].x -a[j].x >= a[j].x -a[k].x){
29                 v = max(v, dp[j][k]+a[j].v);
30                 k--;
31             }
32             dp[i][j] = max(v, dp[i][j]);
33             ans = max(ans, v+a[i].v);
34         }
35     }
36     for (int j = n; j >= 1; j--){
37         int k = j+1, v = a[j].v;
38         for (int i = j-1; i >= 1; i--){
39             while (k <= n && a[j].x -a[i].x >= a[k].x -a[j].x){
40                 v = max(v, dp[j][k]+a[j].v);
41                 k++;
42             }
43             dp[i][j] = max(v, dp[i][j]);
44             ans = max(ans, v+a[i].v);
45         }
46     }
47     printf("%d\n", ans);
48     return 0;
49 }

 

posted @ 2018-10-09 17:16  QAQorz  阅读(243)  评论(1编辑  收藏  举报