UVa 1372 - Log Jumping
Published on 2016-10-25描述
有 根木棍,长度均为 ,左端点的坐标为 ,如果两根木棍 和 满足 ,那就可以从 跳到 (或相反)。你可以从任何一根木棍开始跳,经过其他木棍至多一次,最终回到起跳的木棍,问最多能经过多少个木棍?
分析
我们先将木棍按 从小到大排序,不难发现,一定存在一个最优解,使得经过的木棍 对 有 (通俗的说就是都相邻)。
这样我们对每一个 ,考虑以 为最左的木棍的答案:首先判断 与 是否相交,如果相交,那么就可以构成一个长度为 的环。接着从 开始,顺序考虑能不能加入位置 ,对于 ,考虑 能不能与 和 都相交,如果不可以都相交,那么永远没办法扩大环,更新答案 。否则我们考虑在跳向 的时候跳向 ,然后从 跳回 ,这样就让环增大了 。
这样做复杂度是 的。
一个优化是如果 在 处失败,那么下一次就可以从 处开始,因为在 处失败意味着 与 不相交(也有可能是 就是起点, 与 不相交,这也就是要试一下 的原因,我们假设没发生这种情况),如果从 处开始,那么到 时还是不与 相交,答案不更大。而 与 是有可能相交的,所以我们要从 开始。
这样的话每个点最多被访问 3 次,复杂度降为了 。
代码
// Created by Sengxian on 2016/10/25. // Copyright (c) 2016年 Sengxian. All rights reserved. // UVa 1372 贪心 #include <bits/stdc++.h> using namespace std; typedef long long ll; inline int ReadInt() { static int n, ch; static bool flag; n = 0, ch = getchar(), flag = false; while (!isdigit(ch)) flag |= ch == '-', ch = getchar(); while (isdigit(ch)) n = n * 10 + ch - '0', ch = getchar(); return flag ? -n : n; } const int MAX_N = 5000 + 3; int n, L, x[MAX_N]; int main() { #ifndef ONLINE_JUDGE freopen("test.in", "r", stdin); #endif int caseNum = ReadInt(); while (caseNum--) { n = ReadInt(), L = ReadInt(); for (int i = 0; i < n; ++i) x[i] = ReadInt(); sort(x, x + n); int ans = 1; for (int i = 0, j = 0; i + 1 < n; i = max(i + 1, j - 1)) { #define check(i, j) (x[j] - x[i] <= L) if (check(i, i + 1)) j = i + 2; else continue; while (j < n && check(j - 1, j) && check(j - 2, j)) ++j; ans = max(ans, j - i); } printf("%d\n", ans); } return 0; }