JZOJ #4707 / CODEFORCES #704 B.Ant Man (神奇的DP)

题目描述:

这题改编自cf704b,在数轴上有$n$个点,从一个点跳到另一个点的收益是两点的距离和给出的数组对应下标的值,并且往左和往右的数组不同。要求从一个点起跳,经过每个点刚好一次,最后回到原点,使得收益最大。

解题思路:

因为每个点的贡献只跟跳过来的方向有关,与哪个点跳过来无关。所以可以考虑$dp$,因为最后是一个环,所以每个点的出度和入度都是一。设$F_{i,j,k}$表示前$i$个点还有$j$个点的出边未匹配,$k$个点的入边未匹配。考虑$i+1$个点,有四种情况,左进左出,右进右出,左进右出,右进左出,相应的状态是$F_{i+1,j-1,k-1},F_{i+1,j+1,k+1},F_{i+1,j,k}$,注意到$j$和$k$是恒等的,所以可以简化到二维。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define i64 long long
 5 using namespace std;
 6 
 7 const int N = 5e3 + 10;
 8 const i64 inf = 1e15;
 9 int n, x[N], a[N], b[N], c[N], d[N];
10 i64 f[N][N];
11 
12 int main() {
13     scanf("%d", &n);
14     for (int i = 1; i <= n; i ++) scanf("%d", &x[i]);
15     for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
16     for (int i = 1; i <= n; i ++) scanf("%d", &b[i]);
17     for (int i = 1; i <= n; i ++) scanf("%d", &c[i]);
18     for (int i = 1; i <= n; i ++) scanf("%d", &d[i]);
19     for (int i = 0; i <= n; i ++)
20         for (int j = 0; j <= n; j ++) f[i][j] = -inf;
21     f[0][0] = 0;
22     for (int i = 0; i < n; i ++)
23         for (int j = 0; j <= i; j ++) {
24             if (j) {
25                 f[i + 1][j - 1] = max(f[i + 1][j - 1], f[i][j] + 2 * x[i + 1] + a[i + 1] + c[i + 1]);
26                 f[i + 1][j] = max(f[i + 1][j], f[i][j] + a[i + 1] + d[i + 1]);
27                 f[i + 1][j] = max(f[i + 1][j], f[i][j] + b[i + 1] + c[i + 1]);
28             }
29             f[i + 1][j + 1] = max(f[i + 1][j + 1], f[i][j] - 2 * x[i + 1] + d[i + 1] + b[i + 1]);
30         }
31     printf("%lld", f[n][0]);
32     return 0;
33 }

 

posted @ 2016-08-22 20:16  Awner  阅读(525)  评论(0)    收藏  举报