牛客网 【每日一题】5月9日 过河
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
输入描述:
第一行有一个正整数L(1<=L<=109),表示独木桥的长度。
第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1<=S<=T<=10,1<=M<=100。
第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。 所有相邻的整数之间用一个空格隔开。
输出描述:
只包括一个整数,表示青蛙过河最少需要踩到的石子数。
示例1
输入
10
2 3 5
2 3 5 6 7
输出
2
备注:
对于30%的数据,L<=10000;
对于全部的数据,L<=109。
题解:
首先肯定是想到dp
dp[i]表示走到i这个位置的最小的踩石头的次数
当从位置j调到位置i后,
如果当前位置i没有石头 f [ i ] = min ( f [ i ] , f [ j ] )
如果当前位置i有石头:f[i] = min ( f [ i ], f [ j ] + 1)
就就这样吗?
并不是,看看数据范围,开数组肯定爆了,这是在逼我们做优化
我注意看除了L之外的其他数据,相比之下S,T,M都够小的,像S,T才0到10,那两个石头之间距离很大的话,我们可以调整步伐使得不踩到石头如果这样考虑,两个距离很远的石头之间,我们可以到达任意距离。那距离再长又有何影响。
那我就要考虑两个石头之间距离达到多少才算大呢?
[S,T]是跳跃的范围
当距离Len大于S * T时,len都至少有两种方法可以跳到,(因为S * T等于T个S相加或者S个T相加),之后的距离都可以在修改之前的基础上得到实现。说白了就是距离大于ST之后,都可以到达,那我们把距离大的都缩小到ST,这样L的范围不就限制住了嘛
回归本题,S和T不重复时,S最大是9,T最大是10,S * T最大是90,也就是距离大于90的两个石头
所以我们只需将每两个石头超过 S * T 的距离缩成S * T就可以了
当S=T时,只需要枚举每个石头的坐标是否为s的倍数即可
代码
含注释
#include<bits/stdc++.h>
using namespace std;
const int maxn = 90 * 105;
int s[maxn],a[maxn];
int dp[maxn],len;
bool f[maxn]; //标记改点是否为石头
memset(dp,0x7f,sizeof(dp));
int main()
{
int L,s,t,m;
cin >> L >> s >> t >> m;
len = s * t;
for(int i = 1 ; i <= m ; ++ i)cin >> s[i];
sort(s + 1,s + 1 + m);
if(s == t)//当s与t重复时
{
int sum =0;
for(int i = 1 ; i <= m ; ++ i)
if(s[i] % s == 0)sum++;
printf("%d",sum);
return 0;
}
for(int i = 1 ; i <= m ; ++ i)
{
int d = s[i] - s[i - 1];//两个石头之间的距离
if(d >= len)d = len;//过大的距离进行更新
a[i] = a[i - 1] + d;//将新的石头之间的距离更新到数组a中
f[a[i]] = 1;//更新新的石头
if(i==m)L = a[m] + len;//根据最后一个石头来重新更新独木桥的长度
}
dp[0] = 0;
for(int i = 1 ; i <= L ; ++ i)
for(int j = s ; j <= t ; ++ j)
{
if(i >= j)
{
if(f[i])dp[i] = min(dp[i - j] + 1,dp[i]);
else dp[i] = min(dp[i - j],dp[i]);
}
}
int ans = 200;
for(int i = a[m] ; i <= L ; ++ i)
ans = min(ans,dp[i]);
cout << ans << endl;
return 0;
}