P1052 过河

事后觉得又简单又难。。。

事后觉得又简单又难。。。

这道题如果这个\(l\)不大的话就是一道水得不得了的水题,不过数据那么大就有点难度了。

显然我们可以离散化,具体的操作就是缩点与点之间的距离。我这里用到的是2520缩。

\[2520=lcm(1,2,3,...,10)且1 \leq s \leq t \leq 10 \]

所以我们对相邻两点之间的距离直接%2520。

但注意对\(s=t\)情况的处理。我参考了题解里面的一种做法。

缩完点之后的最后一块石头显然不是终点,真正的终点我们要弄出来。

我们在最后一块石头为首的\(t\)长度区间寻找出答案的最小值,我我们转移状态可能从其中任意元素作为终点,并且我们取答案最小的,就是最优的。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 500005;

int l, s, t, m;

int dp[maxn];
int stone[105], newstone[105], newl;
bool havestone[maxn];

void solve()
{
    int now = 0, ans = 0;
    for(int i = 1; i <= m; i++)
    {
        if((stone[i] - now) % s == 0)
        {
            now = stone[i];
            ans++;
        }
        else if(now + (stone[i] - now) % s <= l) now = now + (stone[i] - now) % s;
    }
    printf("%d\n", ans);
}
int main()
{
    scanf("%d%d%d%d", &l, &s, &t, &m);
    for(int i = 1; i <= m; i++) scanf("%d", &stone[i]);
    std::sort(stone + 1, stone + m + 1);
    memset(dp, 0x3f, sizeof dp);
    for(int i = 1; i <= m; i++)
    {
        newstone[i] = newstone[i - 1] + ((stone[i] - stone[i - 1]) % 2520);
        havestone[newstone[i]] = true;
    }
    dp[0] = 0;
    for(int i = 1; i <= newstone[m] + t; i++)
    {
        for(int j = t; j >= s; j--)
        {
            if(i - j >= 0)
            {
                dp[i] = std::min(dp[i], dp[i - j] + (int)(havestone[i]));
            }
        }
    }
    int ans = 0x3f3f3f3f;
    for(int i = newstone[m]; i <= newstone[m] + t; i++) ans = std::min(ans, dp[i]);
    printf("%d\n", ans);
    return 0;
}
posted @ 2018-10-01 20:54  Garen-Wang  阅读(100)  评论(0编辑  收藏  举报