Easy Climb

题意:

有n块石头,给定他们的高度,现保持第一和最后一块高度不变,其他可增加和减少高度,求通过变换使所有相邻石头的高度差的绝对值不大于d,所变化高度总和的最小值。

分析:

状态还可以想出来,dp[i][j]=min(dp[i-1][k])+abs(s[j]-h[i]),j,k表示i,i-1高度的状态,h[i]为初始高度。但高度太大,高度状态太多,没法下手,看过题解才知道,所有可能的高度状态有hi+kd(1<=i<=n,-n<k<n)种,现在理解的还不透,就可以把状态离散化,再递推就行了,开始可能min(dp[i-1][k])没求好,一直TE。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <complex>
#include <cassert>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const long long inf=1LL<<62;
const int N=110;
const int MAX=N*N*2;
int n,num;
long long h[N],s[MAX],dp[N][MAX],d;
int q[MAX];
void solve()
{
    for(int i=0;i<=n;i++)
        for(int j=0;j<num;j++)
            dp[i][j]=inf;
    int ind=lower_bound(s,s+num,h[1])-s;
    dp[1][ind]=0;
    for(int i=2;i<=n;i++)
    {
        int pre=0,last=0,now=0;
        for(int j=0;j<num;j++)
        {
            while(now<num&&s[now]<=s[j]+d)
            {
                while(pre<last&&dp[i-1][q[last-1]]>=dp[i-1][now])
                    last--;
                q[last++]=now++;
            }
            while(pre<last&&s[j]-d>s[q[pre]])
                pre++;
            dp[i][j]=abs(h[i]-s[j])+dp[i-1][q[pre]];
        }
    }
    ind=lower_bound(s,s+num,h[n])-s;
    if(dp[n][ind]>=inf)
        printf("impossible\n");
    else
        printf("%lld\n",dp[n][ind]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        num=0;
        scanf("%d%lld",&n,&d);
        for(int i=1;i<=n;i++)
            scanf("%lld",&h[i]);
        for(int i=1;i<=n;i++)
            for(long long j=0;j<n;j++)
            {
                s[num++]=h[i]-j*d;
                s[num++]=h[i]+j*d;
            }
        sort(s,s+num);
        num=unique(s,s+num)-s;
        solve();
    }
    return 0;
}

 

posted on 2015-10-12 22:28  积跬步、至千里  阅读(247)  评论(0编辑  收藏  举报

导航