Luogu P1052 过河
gate
设跳到i最少踩到的石子数为f[i],j ∈ (s,t),
c[i]为i是否有石子。
dp方程:f[i] = min(f[i-j]+c[i])
看起来很简单的样子?
但是这道题的数据范围比较奇怪,桥的距离有1e9,显然数组开不下…
不过石子的个数只有100,而且跳的距离只有1~10。
所以两个石子中间可能有很大一段距离没有东西,可以利用这个性质把石子的距离离散化一下。
设相邻两个石子的距离为d。
如果d>t,可以知道,f[i]一定可以由f[i-t]转移过来。
也就是说,当相邻两个石子之间的距离为(d%t)+t+t+...+t时,多出来的t不会对答案造成影响。
那么,可以将距离超过t的相邻石子的距离都改为d%t+t(加t是因为还是一定要跳到中间的一个点)。
因为最后一个可能对答案产生影响的点就是最后一个石子的位置(设为b[m]),
并且只要跳过终点,不一定刚好在终点,
所以答案枚举(b[m],b[m]+t)就可以了。
注意:初始化f[0] = 0
代码如下
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #define MogeKo qwq #include<algorithm> using namespace std; const int maxn = 20005; const int INF = 105; int l,s,t,m,ans; int a[maxn],b[maxn],c[maxn],f[maxn]; int main() { scanf("%d",&l); scanf("%d%d%d",&s,&t,&m); for(int i = 1; i <= m; i++) scanf("%d",&a[i]); sort(a+1,a+m+1); for(int i = 1; i <= m; i++) { int d = a[i]-a[i-1]; if(d <= t) b[i] = b[i-1] + d; else b[i] = b[i-1] + d%t+t; } for(int i = 1; i <= m; i++) c[b[i]] = 1; ans = INF; for(int i = 1;i <= b[m]+t;i++) f[i] = INF; for(int i = s; i <= b[m]+t; i++) for(int j = s; j <= t; j++) f[i] = min(f[i],f[i-j]+c[i]); for(int i = b[m]; i <= b[m]+t; i++) ans = min(ans,f[i]); printf("%d\n",ans); return 0; }