最近作业越来越多了啊, 每天写个每日一题都是奢求
Solution
观察题目数据范围 石子的数目很少 , 青蛙跳的步幅
但是总长度 却是 级别的
假如 很小的话, 我们很容易考虑 表示第 这个位置踩的最小石头数
有转移方程
考虑上图的情况, 在 高达 的时候, 每个石头之间的距离 将会很大
但是这个距离 有很多是无用的情况
为什么呢? 我们可以通过不断的跳缩短距离, 最后决定是否要踩到石头的仅仅是一小段距离
前面的都能通过不停地往前跳抵消掉
那么最后一小段距离最大有多少呢? 我这里取了 , 因为 是 到 的最小公倍数
我们对石头进行缩点, 相邻的距离过大的先对 取模(因为大于等于 总可以通过弹跳抵消)
缩点后总长度会大幅度减小, 数量级别降到了 , 直接做上面的 即可
注意还要特判 的情况, 此时只需要统计 中满足 的情况就行
Code
/* autor: Kurisu */ #include<bits/stdc++.h> using namespace std; typedef long long ll; const long long inf = 1e14; const int N = 1e5 + 5; const double eps = 1e-10; const ll mod = 1e9 + 7; int a[N]; int dp[5000005]; int vis[5000005]; int dist[5000005]; int main() { ios::sync_with_stdio(false), cin.tie(nullptr); int L; int S, T, n; cin >> L >> S >> T >> n; for(int i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + 1 + n); a[n + 1] = L; if(S == T) { // 特判 int cnt = 0; for(int i = 1; i <= n; i++) { if(a[i] % T == 0) { cnt++; } } cout << cnt << "\n"; return 0; } for(int i = 1; i <= n; i++) { dist[i] = (a[i] - a[i - 1]) % 2520; // 缩点 } for(int i = 1; i <= n; i++) { // 缩点 a[i] = a[i - 1] + dist[i]; vis[a[i]] = 1; // 此处有石头 } L = a[n]; //cout << L << "\n"; memset(dp, 0x3f, sizeof(dp)); dp[0] = 0; for(int i = 1; i <= L + T; i++) { for(int j = S; j <= T; j++) { if(i - j >= 0) dp[i] = min(dp[i], dp[i - j] + vis[i]); } } int ans = 1e9; for(int i = L; i <= L + T - 1; i++) { ans = min(ans, dp[i]); } cout << ans << "\n"; return 0; }