【每日一题】 过河 (dp / 数据压缩)

过河

https://ac.nowcoder.com/acm/problem/16655

Solution
题意:
题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
范围:
st 属于[1,10], 石头数量<=100, L<=1e9
思路:
很明显的dp题,dp[i]维护到达 i 点的最少步数:

但是要考虑到木板的范围高大 1e9 ,就需要离散化
因为 st 范围较小,所以我们可以把[1,10]的公倍数求出来,2520,即只要距离超过了2520就可以由[1,10]构造出来。
那么我们可以先对石头排序,然后求出他们相邻的距离,对2520取模,把数据压缩一下。
在枚举的时候我们可以直接把离散后最后的一块石头当成终点,然后枚举1 ~ 终点+t 的每个点,再枚举s~t,dp的方程是:

最后的话,因为题目说明跨过终点也算到达终点,所以ans要在 终点 ~ 终点+t 之间取 min 。
备注:因为我们是枚举每个点以及枚举s~t,所以不用考虑s==t的情况。

Code

#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ll long long
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define io std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;

const int manx=1e6+5;
const int N=1e6+5;

ll a[manx],b[manx],c[manx],dp[manx];

int main(){
    io;
    ll l,s,t,m;   cin>>l>>s>>t>>m;
    for(int i=1;i<=m;i++) cin>>a[i];
    sort(a+1,a+1+m);
    for(int i=1;i<=m;i++) b[i]=(a[i]-a[i-1])%2520;
    for(int i=1;i<=m;i++) a[i]=a[i-1]+b[i],c[a[i]]=1;
    l=a[m];
    memset(dp,inf,sizeof(dp)); dp[0]=0;
    for(int i=1;i<=t+l;i++){
        for(int j=s;j<=t;j++)
            if(i>=j) dp[i]=min(dp[i],dp[i-j]+c[i]);
    }
    ll ans=1e18;
    for(int i=l;i<=t+l;i++) ans=min(ans,dp[i]);
    cout<<ans;
    return 0;
}
全部评论

相关推荐

专心打鱼:互联网搬运工,贴子都要偷
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务