0
点赞
收藏
分享

微信扫一扫

过河(NOIP2005)


​​纱雾小屋​​

​​妖精老师的水晶城堡​​

你真信了?
算了吧!第一个是洛谷,第二个是vijos

过河(NOIP2005)_离散化

过河(NOIP2005)_提高组_02

知识点

离散化

其实这个是很主要的,至于楼下的那一个……没有什么可看的。

动态规划

如楼上所言,这一题中的动态规划很水!

基本思路

对石头坐标排序
离散化并对石头对应位置打标记
动态规划

详细解释

对石头坐标排序

题目没说读入时是有序的,所以我们要先排序,便于离散化。
注意:我们读入是直接保存坐标

离散化并对石头对应位置打标记

为什么要离散化?

因为木桥的长度太大,我们没法用它去建立数组(就是我们dp要用的),所以我们需要离散化

怎么离散化

当相邻的两块石头之间的距离过大时,有些距离是多余的,也就是说我们需要将这一段距离减掉。
那么这个距离有多长呢?
2520
为什么是它?
因为它是1到10这10个数的最小公倍数
我们跳的范围就是1到10的子区间,所以我们任意挑一个跳的距离,就可以一个石子不占的跳过去,并且对后面不会产生影响,所以这就是无用距离,减去即可。
但要注意,如果差距正好是2520的整数倍,那就要少减去一个2520,为了防止两块石头重叠。(感谢ExecutorTassadar指正错误)

打标记

在另一个数组stone[]对应的处理后的坐标位置设置为1,代表有一个石头。

动态规划

我们用f[i]表示到达i位置时,所要踩到的石头的最小数。

那么我们只需要枚举跳的范围,

就得到:

过河(NOIP2005)_NOIP2005_03

这就是状态转移方程。

难度点评

不是很难,如果知道离散化的话!

代码

(感谢ExecutorTassadar指正错误)

#include<bits/stdc++.h>
using namespace std;
int minn,maxx,m,l,i,j,f[300000],a[1000],sum,k=0;
bool stone[300000];
int main()
{
scanf("%d%d%d%d",&l,&minn,&maxx,&m);
for (i=1;i<=m;++i){
scanf("%d",&a[i]);
}
sort(a+1,a+m+1);
for (i=1;i<=m;++i){
if (a[i]-a[i-1]>2520){
k+=(a[i]-a[i-1])/2520;
if((a[i]-a[i-1])%2520==0){
k--;
}
}
stone[a[i]-k*2520]=1;
}
memset(f,0x3f,sizeof(f));
f[0]=0;
for (i=1;i<=252000;++i){
for (j=maxx;j>=minn;--j){
if (i-j>=0){
f[i]=min(f[i-j]+stone[i],f[i]);
}
}
}
printf("%d",f[252000]);
return 0;
}


举报

相关推荐

0 条评论