首先,这题有个关键的地方就是要想到虽然它的高度很大,有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;
}