HDU-2770-Easy Climb

131 篇文章 0 订阅

题意:这个题是给你一个序列,然后你对于首尾2个值不能改动,其他的值你可以改动,要求你通过修改使得相邻2个值之差绝对值不超过d,然后修改的代价为修改后的值域原来值差的绝对值之和。

思路:其实白书上面说了一些思路的(新版的小白书),不得不佩服上面提到的修改后的状态必然为hi+kd(1<=i<=n,-n<k<n)这样就转为n^2了,可以用dp[i][x]表示当前为i,状态为x满足题意的最少代价,则转移方程式为dp[i][x]=abs(h[i]-x)+min(dp[i-1][y]( x-d<=y<=x+d),还需要注意的是这个题需要离散化,然后需要各种long long

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const long long inf=1LL<<62;
const int maxn=110;
const int maxm=maxn*maxn*2;
int n,cnt;
long long h[maxn],s[maxm],dp[maxn][maxm],d;
int q[maxm];
void Init()
{
    for(int i=0;i<=n;i++)
        for(int j=0;j<cnt;j++)
            dp[i][j]=inf;
}
void solve()
{
    Init();
    int ind=lower_bound(s,s+cnt,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<cnt;j++)
        {
            while(now<cnt&&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+cnt,h[n])-s;
    if(dp[n][ind]>=inf)
        printf("impossible\n");
    else
        printf("%I64d\n",dp[n][ind]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        cnt=0;
        scanf("%d%I64d",&n,&d);
        for(int i=1;i<=n;i++)
            scanf("%I64d",&h[i]);
        for(int i=1;i<=n;i++)
            for(long long j=0;j<n;j++)
            {
                s[cnt++]=h[i]-j*d;
                s[cnt++]=h[i]+j*d;
            }
        sort(s,s+cnt);
        cnt=unique(s,s+cnt)-s;
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值