BZOJ-1742: [Usaco2005 nov]Grazing on the Run 边跑边吃草

[文章目录]

Description

给你一个数轴,有n个位置,p1~pn。你的初始位置为L。每一秒,当前存在的未达到的位置的代价+1。每一秒你能走一个单位。到达一个位置的时候,可以将该位置删掉,花费相应的代价。询问将所有位置都删掉的最小代价。n<=1000 p<=10^6

区间DP。
一旦走到一个存在的位置肯定删除,那么每个时刻删除的区间一定是连续的一段,并且包含L。
设dp[i][j]表示第i个位置到底j个位置都删掉了的最小代价。当前在第i个位置。转移两种情况,i->i-1 i->j+1。
发现转移的时候并不知道当前时间。发现统计代价的方式可以转换一下,表示所有点的代价和(不管是否存在)。转移的时候累加时间乘以当前存在的点的个数。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int n,L,pos[1010];
ll dp[1010][1010];
inline ll Abs(ll x){return x>0?x:-x;}

int main() 
{
    scanf("%d%d",&n,&L);
    for(int i=1;i<=n;++i) scanf("%d",pos+i);
    sort(pos+1,pos+n+1); memset(dp,0x3f,sizeof dp);
    int l=1,r=n+1,mid;
    while(l<r)
    {
        mid=(l+r)>>1;
        if(pos[mid]>=L) r=mid;
        else l=mid+1;
    }
    if(r<=n&&r>=1&&pos[r]>=L) dp[r][r]=Abs(pos[r]-L)*n;
    if(r-1<=n&&r-1>=1&&pos[r-1]<L) dp[r-1][r-1]=Abs(pos[r-1]-L)*n;
    for(int i=0;i<n;++i)
    {
        for(int j=1;j+i<=n;++j)
        {
            if(j!=1)
            {
                dp[j-1][j+i]=min(dp[j-1][j+i],dp[j][j+i]+Abs(pos[j]-pos[j-1])*(n-i-1));
                dp[j-1][j+i]=min(dp[j-1][j+i],dp[j+i][j]+Abs(pos[j+i]-pos[j-1])*(n-i-1));
            }
            if(j+i!=n)
            {+
                dp[j+i+1][j]=min(dp[j+i+1][j],dp[j][j+i]+Abs(pos[j]-pos[j+i+1])*(n-i-1));
                dp[j+i+1][j]=min(dp[j+i+1][j],dp[j+i][j]+Abs(pos[j+i]-pos[j+i+1])*(n-i-1));
            }
        }
    }
    printf("%lld",min(dp[1][n],dp[n][1]));
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注