'commit'
This commit is contained in:
73
TangDou/CSP-J/AcWingTraining/T1/484.cpp
Normal file
73
TangDou/CSP-J/AcWingTraining/T1/484.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
const int N = 10020; // 定义一个足够大的数组空间
|
||||
|
||||
// 全局变量声明
|
||||
int L, S, T, m; // L:桥长度, S:最小跳跃距离, T:最大跳跃距离, m:石子数量
|
||||
int stones[N]; // 存储石子的位置
|
||||
int w[N]; // 记录每个位置是否有石子(离散化后)
|
||||
int f[N]; // dp数组,f[i]表示跳到位置i最少需要踩的石子数
|
||||
|
||||
int main() {
|
||||
// 读入基本数据
|
||||
cin >> L >> S >> T >> m;
|
||||
|
||||
// 特殊情况处理:当最小跳跃距离等于最大跳跃距离时
|
||||
// 此时青蛙只能跳固定距离S
|
||||
if (S == T) {
|
||||
int res = 0;
|
||||
while (m--) {
|
||||
int x;
|
||||
cin >> x;
|
||||
// 如果石子位置是S的倍数,青蛙一定会踩到
|
||||
if (x % S == 0)
|
||||
res++;
|
||||
}
|
||||
printf("%d\n", res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 读入所有石子的位置
|
||||
for (int i = 0; i < m; i++)
|
||||
cin >> stones[i];
|
||||
sort(stones, stones + m); // 将石子位置从小到大排序
|
||||
|
||||
// 核心算法:离散化处理
|
||||
int last = 0, k = 0; // last:上一个处理的位置, k:离散化后的新位置
|
||||
for (int i = 0; i < m; i++) {
|
||||
// 重要优化:基于数论的优化
|
||||
// 当两个相邻石子距离过大时,中间的空隙可以被压缩
|
||||
// 91是基于(p-1)(q-1)-1+20得来,其中p=10,q=9
|
||||
// 这个优化基于:当两点距离大于91时,一定可以通过组合S和T的跳法到达
|
||||
// 核心:桥太长,无法遍历,但有一个突破口,就是石子数量有限
|
||||
// 如何利用这点呢?使用上面的定理,我们知道,间距太大的间隙可以被压缩,只有大于91的空隙,就可以压缩
|
||||
// 如何压缩,压缩完是什么样的东西呢?
|
||||
// 就是把无意义的没有石子的位置移除掉!无意义的是指肯定能通过ST踩到的并且无石子的位置
|
||||
// 有意义的就是可能踩到也可能踩不到的位置,这些位置保留下来,无意义的干掉就行了。
|
||||
// 下面的循环,枚举的是两个相邻石子之间的空位。
|
||||
for (int j = 0; j < min(stones[i] - last, 91); j++)
|
||||
w[++k] = 0; // 在新的离散化空间中标记无石子的位置
|
||||
w[k] = 1; // 标记有石子的位置
|
||||
last = stones[i];
|
||||
}
|
||||
|
||||
// 动态规划初始化
|
||||
memset(f, 0x3f, sizeof(f)); // 预求最大先设最小
|
||||
f[0] = 0; // 注意边界的初始化,思考现实含义:位置 0最少需要踩的石子数为 0
|
||||
// 动态规划过程
|
||||
for (int i = 1; i <= k + T; i++) {
|
||||
// 枚举所有可能的跳跃距离
|
||||
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; i < k + T; i++)
|
||||
res = min(res, f[i]);
|
||||
|
||||
printf("%d\n", res);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user