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;
}