你真信了?
算了吧!第一个是洛谷,第二个是vijos
知识点
离散化
其实这个是很主要的,至于楼下的那一个……没有什么可看的。
动态规划
如楼上所言,这一题中的动态规划很水!
基本思路
对石头坐标排序
离散化并对石头对应位置打标记
动态规划
详细解释
对石头坐标排序
题目没说读入时是有序的,所以我们要先排序,便于离散化。
注意:我们读入是直接保存坐标
离散化并对石头对应位置打标记
为什么要离散化?
因为木桥的长度太大,我们没法用它去建立数组(就是我们dp要用的),所以我们需要离散化
怎么离散化
当相邻的两块石头之间的距离过大时,有些距离是多余的,也就是说我们需要将这一段距离减掉。
那么这个距离有多长呢?
2520
为什么是它?
因为它是1到10这10个数的最小公倍数
我们跳的范围就是1到10的子区间,所以我们任意挑一个跳的距离,就可以一个石子不占的跳过去,并且对后面不会产生影响,所以这就是无用距离,减去即可。
但要注意,如果差距正好是2520的整数倍,那就要少减去一个2520,为了防止两块石头重叠。(感谢ExecutorTassadar指正错误)
打标记
在另一个数组stone[]对应的处理后的坐标位置设置为1,代表有一个石头。
动态规划
我们用f[i]表示到达i位置时,所要踩到的石头的最小数。
那么我们只需要枚举跳的范围,
就得到:
这就是状态转移方程。
难度点评
不是很难,如果知道离散化的话!
代码
(感谢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;
}