标签:
Bob是一个魔法师。这天,他被N座山所阻挡,这些山排成一排,每座山有一个高度。Bob需要从左往右每次跳到相邻的一座山上,相邻的两座山的高度差不能超过K,当从高度差为D的一座山跳到另一座山时要花A×D的魔法值。Bob可以改变一座山的高度,但调整后的高度不能小于0或大于1000,改变S的高度需要花费S×S的魔法值。现在已知每座山的高度,求Bob跳完所有山后魔法值的最少花费。
第一行一个整数T(T≤150),表示数据组数。
每组第一行有3个整数N(1≤N≤1000), K(0≤K≤1000), A(0≤A≤1000)。
接下来N个整数,按从左往右的顺序表示山的高度,山的高度在0到1000之间。
对于每组数据,输出一个整数,表示最少花费。
Sample Input | Sample Output |
---|---|
2 1 1 1 1 3 1 10 1 2 3 |
0 2 |
解题报告:
我们令f( i , j ) 将第 i 座山高度改为 j 的最小花费.
F( i , j ) = min ( f( i – 1 , k ) + abs ( j – k ) + (i – h[i]) ^ 2)
不妨有 j > k
F( i , j ) = min ( f( i – 1 , k ) – k ) + j + (i – h[i]) ^ 2
即维护一个单调队列来更新 j > k的情况.
J < k 的情况同理.
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> typedef long long ll; using namespace std; const int maxn = 1e3 + 50; int a,n,dl,q[maxn]; ll f[maxn][maxn],h[maxn]; int main(int argc,char *argv[]) { int Case; scanf("%d",&Case); while(Case--) { scanf("%d%d%d",&n,&dl,&a); //DL = deeplimit for(int i = 1 ; i <= n ; ++ i) scanf("%lld",&h[i]); for(int i = 1 ; i <= n ; ++ i) for(int j = 0 ; j <= 1000 ; ++ j) f[i][j] = 999999999999; for(int i = 0 ; i <= 1000 ; ++ i) f[1][i] = (i-h[1])*(i-h[1]); for(int i = 2 ; i <= n ; ++ i) { int front = 0 , rear = 0; for(int j = 0 ; j <= 1000 ; ++ j) { while(rear > front && f[i-1][q[rear-1]] - a*q[rear-1] >= f[i-1][j] - a*j) rear--; q[rear++] = j; while(rear - front > 1 && j > q[front] + dl) front++; f[i][j] = min(f[i][j],(j-h[i])*(j-h[i]) + f[i-1][q[front]] + (j - q[front]) * a); } front = rear = 0; for(int j = 1000 ; j >= 0 ; -- j) { while(rear > front && f[i-1][q[rear-1]] + q[rear-1]*a >= f[i-1][j] + j*a) rear--; q[rear++] = j; while(rear - front > 1 && q[front] > j + dl) front++; f[i][j] = min(f[i][j],(j-h[i])*(j-h[i]) + f[i-1][q[front]] + (q[front] - j) * a ); } } ll ans = 999999999999; for(int i = 0 ; i <= 1000 ; ++ i) ans = min(ans,f[n][i]); printf("%lld\n",ans); } return 0; }
UESTC_最少花费 2015 UESTC Training for Dynamic Programming<Problem D>
标签:
原文地址:http://www.cnblogs.com/Xiper/p/4539614.html