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