首先,这题有个关键的地方就是要想到虽然它的高度很大,有10^9次方,但是实际上它的有效状态的高度只有h[i] +- k * d (k: 0 .. n-1)这么多,就是最多2*n^2个有效的高度
至于为什么是只有2*n^2的有效高度,请移步http://hi.baidu.com/sunhaowenprime/item/f7a379ba187467f663388e2d zjut_DD大牛的讲解
基于这个条件,就可以很容易得出DP状态转移方程:dp[i][j] = min(dp[i-1][k] + abs(nh[j] - h[i])), nh[]表示2*n^2个有效的离散的高度值。
然后这个用单调队列就可以将转移优化至O(1), 总时间复杂度为O(n^3)
#define pb push_back #define mp make_pair #define fi first #define se second #define all(a) (a).begin(),(a).end() #define FOR(i,a,b) for (int i=(a);i<(b);i++) #define FORD(i,a,b) for (int i=(a); i>=(b); i--) #define REP(i,b) FOR(i,0,b) #define sf scanf #define pf printf using namespace std; const int maxint = -1u>>1; const double pi = 3.14159265358979323; const double eps = 1e-8; const long long inf = 1LL << 60; typedef pair<int,int> pii; typedef vector<int> vi; typedef vector<int>::iterator vit; int n; long long d; long long h[110]; inline long long ABS(long long x) { return x >= 0 ? x : -x; } vector<long long> b; long long dp[2][110*510]; int main() { int T; sf("%d", &T); while (T--) { sf("%d%I64d", &n, &d); REP(i, n) sf("%I64d", &h[i]); if (ABS(h[0] - h[n-1]) > 1LL * (n - 1) * d) { pf("impossible\n"); continue; } b.clear(); REP(i, n) { for (long long j = -(n-1); j <= n-1; j++) b.pb(h[i] + j * d); } sort(all(b)); b.erase(unique(all(b)), b.end()); int m = b.size(), p = 0, q; REP(i, m) if (b[i] != h[0]) dp[p][i] = inf; else dp[p][i] = 0; FOR(i, 1, n) { q = p ^ 1; REP(j, m) dp[q][j] = inf; int k = 0; REP(j, m) { while (k < m && b[k] < b[j] - d) k++; while (k+1 < m && b[k+1] <= b[j] + d && dp[p][k+1] <= dp[p][k]) k++; dp[q][j] = min(dp[q][j], dp[p][k] + ABS(b[j] - h[i])); } p = q; } REP(i, m) if (b[i] == h[n-1]) { pf("%I64d\n", dp[p][i]); break; } } return 0; }