UESTC 我要长高

来源:互联网 发布:日本学校现代网络神曲 编辑:程序博客网 时间:2024/04/27 20:39

我要长高 (dp加优化)

题目链接:我要长高

题意是……就是题目描述的那样了吧 题意很显而易见,一眼dp题
dp[i][j]代表第i个人身高为j时的最小消耗,
dp[i][j] = min (dp[i-1][k] + abs(j - k ) * C + (j - h[i])^2)
复杂度O(n * h[i]^2 ),很明显有点大,学习了一下单调队列优化dp之后,发现形如dp[i] = min/max (dp[j]) + x[i]的方程,一般可以用单调队列优化。
然后我们试着把方程变形一下
当第i个人身高比前一个高的时候
dp[i][j] = min( dp[i-1][k] - k * C + j * C + (j - h[i]) ^ 2 ) (1 <= k <= j)
那么令F[i-1][k] = dp[i-1][k] - k * C , X[i][j] = j * C + (j - h[i]) ^ 2 (先忽略i这个变量),则原方程可以看成dp[j] = min(F[k]) + X[j] ,因此可以用单调队列来优化,不过这里的k取值范围是(1, j) ,所以即使不用单调队列也是可以的,直接令f[i][j] 为 min(dp[i][k] - k * C) 直接递推就行
当第i个人身高比前一个矮的时候同理。令f[i][j]为j到100里面dp[i][k] + k * C的最小值,倒着递推即可。
但是有时候如果对k的取值范围有所限制,(比如限定某一固定长度的区间时)就需要用到单调队列了。

#include<cmath>#include<algorithm>#include<cstring>#include<string>#include<set>#include<map>#include<time.h>#include<cstdio>#include<vector>#include<list>#include<stack>#include<queue>#include<iostream>#include<stdlib.h>using namespace std;#define  LONG long longconst int   INF=0x3f3f3f3f;const int MOD=1e9+ 7;const double PI=acos(-1.0);#define clrI(x) memset(x,-1,sizeof(x))#define clr0(x) memset(x,0,sizeof x)#define clr1(x) memset(x,INF,sizeof x)#define clr2(x) memset(x,-INF,sizeof x)#define EPS 1e-10#define lson  l , mid , rt<< 1#define rson  mid + 1 ,r , (rt<<1)+1#define root 1, m , 1int  dp[2][110] ;int h[51000] ;int f[2][110] ;int f2[2][110] ;int main(){    int n ;    int C ;    while(~scanf("%d",&n))    {        scanf("%d",&C) ;        for(int i = 1; i <= n ; ++i)            scanf("%d",&h[i]) ;        clr1(dp) ;        clr1(f) ;        clr1(f2) ;        //爆空间了,所以用滚动数组。        int now = 0 , pre  = 1 ;        for(int j = h[1] ; j <= 100 ; ++ j)            dp[1][j] = (j - h[1]) * (j - h[1]) ;        for( int j = 1 ; j <= 100 ; ++ j)            f[1][j] = min (f[1][j-1] , dp[1][j] - j * C) ;        for(int j = 100 ; j >= 1 ; -- j)            f2[1][j] = min(f2[1][j+1] , dp[1][j] + j * C) ;        for(int i = 2;i <= n ; ++ i)        {            clr1(dp[now]) ;            clr1(f[now]) ;            clr1(f2[now]) ;            for(int j = h[i] ; j <= 100 ; ++ j)                dp[now][j] = min( dp[now][j] , (j - h[i]) * (j - h[i]) + j * C + f[pre][j]  );            for(int j = 100 ; j >= h[i] ; -- j)                dp[now][j] = min(dp[now][j] , (j - h[i])* (j - h[i]) - j * C  + f2[pre][j]) ;            for(int j = 1 ; j <= 100 ; ++j)                f[now][j] = min(f[now][j-1] , dp[now][j] - j * C );            for(int j = 100 ; j >= 1 ; -- j)                f2[now][j] = min (f2[now][j + 1] , dp[now][j] + j * C ) ;            now ^= 1 ;            pre ^= 1 ;        }        int ans = INF ;        for(int i = h[n] ; i <= 100 ; ++ i)ans = min(ans , dp[pre][i]) ;        printf("%d\n",ans) ;    }}
1 0
原创粉丝点击