[HDU 6157]The Karting
description
solution
先用前缀和求出di:1→id_i:1\rightarrow idi:1→i 的距离
前缀和满足:若在iii点进行方向改变,则iii产生的贡献是一定的,可以先累计贡献
也就是说真正的路径怎么走,我们是不关心的,只关心在哪些点进行了转向操作
设fi,j,k:f_{i,j,k}:fi,j,k: 前iii个点选了jjj个特别点left→rightleft\rightarrow rightleft→right比right→leftright\rightarrow leftright→left转向多kkk个
-
iii点不是特别点
fi−1,j,k→fi,j,kf_{i-1,j,k}\rightarrow f_{i,j,k}fi−1,j,k→fi,j,k
-
iii点是特别点,但iii处不转向
fi−1,j−1,k→fi,j,kf_{i-1,j-1,k}\rightarrow f_{i,j,k}fi−1,j−1,k→fi,j,k
-
iii点left→rightleft\rightarrow rightleft→right转向
fi−1,j−1,k−1+D−2⋅di→fi,j,kf_{i-1,j-1,k-1}+D-2·d_i \rightarrow f_{i,j,k}fi−1,j−1,k−1+D−2⋅di→fi,j,k
-
iii点right→leftright\rightarrow leftright→left转向
fi−1,j−1,k+1+D+2⋅di→fi,j,kf_{i-1,j-1,k+1}+D+2·d_i\rightarrow f_{i,j,k}fi−1,j−1,k+1+D+2⋅di→fi,j,k
答案即为fn,m,0f_{n,m,0}fn,m,0
最后一定是个环,两种类型的转向次数一定是相同的
因为did_idi是前缀和,根据dpdpdp的设定,显然多的转向类型产生的贡献是−-−,靠另一种转向进行抵消
code
#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 105
#define inf 0x3f3f3f3f
int n, m, D;
int d[maxn];
int f[maxn][maxn][maxn];int main() {while( ~ scanf( "%d %d", &n, &m ) ) {scanf( "%d", &D );d[1] = 0;for( int i = 2;i <= n;i ++ ) {scanf( "%d", &d[i] );d[i] += d[i - 1];}for( int i = 0;i <= n;i ++ )for( int j = 0;j <= m;j ++ )for( int k = 0;k <= m;k ++ )f[i][j][k] = -inf;f[0][0][0] = 0;//f(i,j,k):前i个数选了j个标记点且从左到右转向个数比从右到左转向个数多k个的最大收益 for( int i = 1;i <= n;i ++ ) {f[i][0][0] = 0;for( int j = 1;j <= min( i, m );j ++ ) {for( int k = 0;k <= j;k ++ )f[i][j][k] = max( f[i - 1][j][k], f[i - 1][j - 1][k] );//不转向i距离就会该方向上的更远点的d算进去 所以不再加d[i] for( int k = 0;k < j;k ++ )f[i][j][k] = max( f[i][j][k], f[i - 1][j - 1][k + 1] + D + ( d[i] << 1 ) );for( int k = 1;k <= j;k ++ )f[i][j][k] = max( f[i][j][k], f[i - 1][j - 1][k - 1] + D - ( d[i] << 1 ) );}}printf( "%d\n", f[n][m][0] );}return 0;
}