题解 P1052 【过河】
1.30分做法(理论上只有30分)
实际上却有40分
首先我们看一下题意,可以 猜 看出是线性dp
1.状态定义
我们要定义的状态肯定是在某种情况下的跳最少石子数,那么这个石子数与且只与目前的位置有关。
所以我们定义:dp[i]表示从1跳到第i个点的最小踩石子数。
2.转移方程
dp[i]可能从哪里来呢:它一定是从前面的某个状态转移来的,且它只与前面dp[j]的值、当前位置有无石子有关
我们枚举j,j表示上一步跳的距离,当然s<=j<=t。
stone[i]表示第i个位置有i个石子,i只为0,1
所以就是 dp[i]=min(dp[i],dp[i-j]+stone[i]);
3.枚举范围
这里提醒大家亿下,蒟蒻枚举时把i从1开始枚了,调了很久,应从s开始枚,因为i<s的点都不可能跳到,第一个可以跳到的是s
所以: i从s到l枚举,j从s到t枚举。
4.特判
题目中给的是“s<=t”所以s==t时,只有1种跳法,所以无论你怎么跳。答案都固定,就是 q[i]表示第i块石子的位置,如果q[i]是s的倍数;这颗石子就必须要踩
5.答案(坑)
因为青蛙可能跳到大于l的位置(但小于l+t),因为题目中的叙述“当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥” 所以输出dp[l]是错的,应输出min(dp[i~n+t-1]); 下面就是反例 l=7,答案存在dp[8]中。 应输出0, 如果输出dp[7]会输出inf。 7 4 5 1 5
1_2_3_4_5(石头)_6_7---8
为什么不画个图呢?当然是因为懒啊
这里dp[8]里存的才是答案,因为从4不可能到7
code:
#include<bits/stdc++.h>
using namespace std;
int l,s,t,m,stone[10000001],p,dp[1000001],q[101];
int main()
{
cin>>l>>s>>t>>m;
for(int i=1;i<=m;++i)
cin>>q[i];
if(s==t)
{
int s=0;
for(int i=1;i<=m;++i)
if(q[i]%t==0) s++;
cout<<s;
return 0;
}//特判
sort(q+1,q+m+1);
for(int i=1;i<=m;++i)
{
p+=q[i]-q[i-1];
stone[p]=1;
}
dp[0]=0;memset(dp,0x3f,sizeof(dp));
for(int i=s;i<=p+9;++i)
for(int j=s;j<=t;++j)
{
dp[i]=min(dp[i],dp[i-j]+stone[i]);
}
int ans=0x7fffffff;
for(int i=p;i<=p+t;++i)
ans=min(ans,dp[i]);
cout<<ans;
return 0;
}
100 分做法
看了看难度,啊呸数据范围:l<=10^9 ??? 这题一定不只是一个线性dp。
如果用线性dp,复杂度约为O(n*(s-t)) 也就是O(10n),不仅会T,
你还要开一个10^9的数组
路径压缩
读一读题,就会发现桥上的石子分布是很稀疏的,平均每10^8才会有一块,所以我们就把两颗石子多余某数的距离化为某数。
这个“某数”一定是j的倍数,这样就相当于可以给青蛙一个休息,缓一缓的距离。(只可意会不可言传)
又因为j要大于等于1,小于等于10(1<=s,t<=10)
所以“某数”为1~10的最小公倍数:2520
只用在读入后求stone数组时把距离取 min(距离,2520)就可以辣。
code:
#include<bits/stdc++.h>
using namespace std;
int l,s,t,m,stone[252010],p,dp[252010],q[101];//stone数组的252010 就约是每两格的距离最大值2520*格数最大值99
int main()
{
cin>>l>>s>>t>>m;
for(int i=1;i<=m;++i)
cin>>q[i];
if(s==t)
{
int s=0;
for(int i=1;i<=m;++i)
if(q[i]%t==0) s++;
cout<<s;
return 0;
}//特判
sort(q+1,q+m+1);//不排序会RE
for(int i=1;i<=m;++i)
{
p+=min(q[i]-q[i-1],2520);
stone[p]=1;
}
dp[0]=0;memset(dp,0x3f,sizeof(dp));
for(int i=s;i<=p+9;++i)
for(int j=s;j<=t;++j)
{
dp[i]=min(dp[i],dp[i-j]+stone[i]);
}
int ans=0x7fffffff;
for(int i=p;i<=p+t;++i)
ans=min(ans,dp[i]);
cout<<ans;
return 0;
}
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970996,谢谢你的阅读或转载!