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
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/mogeko/p/11649546.html