UVa12170
这道题我想出了一部分,还有另一部分没有想出,说明还需努力。
先说一说我想到的部分吧,首先用d(i,j)表示修改了前i个数,最后一个数为j(高度)所能够得到的最少花费,这个不难想到,
但是由于n<=10^9所以对时间空间来讲是行不通的,于是需要修改状态的定义,我想,这道题的高度j一定是一个特殊值,如果j取
任意都行的话那就不能够省去空间里,所以可能高度为前一个的顶部、不变(如果在范围内)、底部,然后就想不出来什么了。
我的思路是正确的,但差就差在推广与延伸,我们可以通过举3个数的例子不难看出一定是顶部、中间、底部(其实三个数可以证明,
多了我不会证,但在有时比赛上这种感觉往往是对的),我当时仅仅知道高度是前一个的顶部、不变、底部,并没有想到对于整体来说
高度的取值的规律,通过书的解释,我也明白了每个数修改之后一定可以写成hp+kd的形式,这样我们的状态数量变成了O(n^3)(可以看别的博客上面的说明),后面还有单调队列(与滑动窗口或使用数据结构)这个非常的巧妙,书上说平摊时间复杂度为O(1)(我
不知道平摊时间复杂度是什么?),然后感觉实现起来不好写(滑动窗口),看来刘汝佳代码发现十分巧妙(学到了),下面就是
代码:
// UVa 12170 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 100 + 5; const int maxx = maxn*maxn*2; const LL INF = (1LL<<60); LL h[maxn], x[maxx], dp[2][maxx]; LL d; int main() { int T, n; scanf("%d", &T); while (T--) { scanf("%d%lld", &n, &d); for (int i = 0; i < n; ++i) scanf("%lld", &h[i]); if (abs(h[0]-h[n-1]) > (n-1)*d) { printf("impossible\n"); continue; } int x_size = 0; for (int i = 0; i < n; ++i) for (int k = -n+1; k <= n-1; ++k) x[x_size++] = h[i] + k*d; sort(x, x+x_size); int nx = unique(x, x+x_size) - x; int t = 0; for (int i = 0; i < nx; ++i) { dp[t][i] = INF; if (x[i] == h[0]) dp[t][i] = 0; } for (int i = 1; i < n; ++i) { int k = 0; for (int j = 0; j < nx; ++j) { while (k < nx && x[k] < x[j]-d) k++; while (k+1 < nx && x[k+1] <= x[j]+d && dp[t][k+1] <= dp[t][k]) k++; if (dp[t][k] == INF) dp[t^1][j] = INF; else dp[t^1][j] = dp[t][k] + abs(h[i]-x[j]); } t ^= 1; } for (int i = 0; i < nx; ++i) if (x[i] == h[n-1]) printf("%lld\n", dp[t][i]); } return 0; }
语言c++计算机程序设计爱好者
不定期更新题目题解
望互相分享心得体会
有意留言加q