算法知识点: 动态规划,数学
复杂度:
解题思路:
如果不考虑 的范围,那么就是一道简单的DP问题:
- 状态表示
表示走到位置
,踩到的石头个数的最小值;
- 状态计算
, 其中
表示第
个位置是否有石头,
在
到
之间。
那么当 很大时该怎么办呢,我们发现虽然
是
级别,但石头总数很少,最多只有
个,因此两个石头之间可能有很长的“空隙”。
接下来分两种情况讨论:
- 如果
,那么走法唯一,石头位置是
整数倍的一定会被踩,否则一定不会被踩,直接遍历一遍所有石头即可;
- 如果
,那么我们考虑不能被
所表示的数有哪些,如果我们只用两个相邻的数
,那么不能被表示的数的最大值是
,因此所有大于等于
的数一定可以被
表示出来,当
时取到最大值,此时
,因此所有大于等于72的数,一定可以被
表示出来。当第一次越过第
个石头时,青蛙的位置一定在该石头右侧十步以内;当即将跳过第
个石头时,青蛙一定在第
个石头左侧十步以内。那么当中间部分的长度大于100时我们可以将线段的长度缩短为100,得到的结果是等价的。那么此时最多只会用到
个位置,复杂度可以接受了。
C++ 代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; const int N = 10020;
int n, S, T, m;
int stones[N];
int w[N], f[N];
int main()
{
scanf("%d%d%d%d", &n, &S, &T, &m);
if (S == T)
{
int res = 0;
while (m--)
{
int x;
scanf("%d", &x);
if (x % S == 0) res++;
}
printf("%d\n", res);
}
else
{
for (int i = 0; i < m; i++) scanf("%d", &stones[i]);
sort(stones, stones + m);
int last = 0, k = 0;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < min(stones[i] - last, 100); j++)
w[++k] = 0;
w[k] = 1;
last = stones[i];
}
for (int i = 1; i <= k + 10; i++)
{
f[i] = 1e9;
for (int j = S; j <= T; j++)
if (i - j >= 0)
f[i] = min(f[i], f[i - j] + w[i]);
}
int res = 1e9;
for (int i = k + 1; i <= k + 10; i++) res = min(res, f[i]);
printf("%d\n", res);
}
return 0;
} 
京公网安备 11010502036488号