bzoj 3379 - [USACO2004] 交作业

Description

一个数轴上有 \(n \le 1000\) 个位置, 每个位置有一个时间 \(t_i\)

要求在 时刻 \(t_i\) 后, 至少经过该位置一次. (去交作业)

求从 \(0\) 号点出发前往 \(B\) 号点, 满足上述条件的最小需要时间

Solution 1

CQzhangyu的做法. 非常的妙啊

\(\ge t\) 不好做, 走过的位置以后可能又会突然冒出一个人, 决策的顺序位置.

考虑反着来, 先二分答案 \(Ans\), 并从 \(B\)\(0\) 走.

这样限制条件变成了 \(\le Ans - t_i\), 这样就之用在限制时间内经过一次该点即可

直接使用区间dp, 复杂度 \(O(n^2\log n)\)

Solution 2

考虑初始状态 \([1, n]\) 区间均未交作业

接着你会进去区间内乱走一通, 交一些作业. 且此时你一直没有交边界的作业

但是边界的作业迟早是要交的, 两个边界中, 必有一个是 先被到达的

不妨设 \([a,b]\) 先到达了 \(a\), 那么接下来, \(b\) 一定是要过去的, 中间的点都是必须被经过的.

而这些中间被经过的, 若是在乱走到达 \(a\) 之前交了作业, 将其换至 到 \(a\) 后往 \(b\) 走的过程中再交是没有影响的.

于是, 最优的决策, 一定是选择区间的一端 先交作业

接着就可以使用区间dp, 区间从大往小走就好了

Notice

坐标有 \(0\)

Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rep(i, a, b) for (int i = (a), _ = (b); i <= _; ++ i)
#define per(i, a, b) for (int i = (a), _ = (b); i >= _; -- i)
#define For(i, a, b) for (int i = (a), _ = (b); i < _; ++ i)
#define ri rd<int>
using namespace std;
const int N = 1007;
const int INF = 1e9 + 7;

template<class T> inline T rd() {
    bool f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = 0;
    T x = 0; for (; isdigit(c); c = getchar()) x = x * 10 + c - 48; return f ? x : -x;
}

int m, n, cur;
int t[N];
int f[N][N];
int lf, rt;

int main() {
#ifndef ONLINE_JUDGE
    freopen("a.in", "r", stdin);
#endif

    m = ri(), n = ri(), cur = ri() + 1;

    lf = n + 1, rt = 0;
    rep (i, 1, m) {
        int x = ri() + 1, y = ri();
        t[x] = max(t[x], y);
        lf = min(lf, x), rt = max(rt, x);
    }
    
    memset(f, 0x3f, sizeof f);
    f[lf][rt] = max(lf - 1, t[lf]), f[rt][lf] = max(rt - 1, t[rt]);

    per (l, rt-lf-1, 0) rep (i, lf, rt - l) {
        int j = i + l;
        f[i][j] = min(f[i][j], max(t[i], min(f[i-1][j] + 1, f[j+1][i] + ((j + 1) - i))));
        f[j][i] = min(f[j][i], max(t[j], min(f[i-1][j] + (j - (i - 1)), f[j+1][i] + 1)));
    }
    
    int res = INF;
    rep (i, lf, rt) res = min(res, f[i][i] + abs(i - cur));
    printf("%d\n", res);

    return 0;
}
posted @ 2017-11-01 20:40  _zwl  阅读(...)  评论(...编辑  收藏