某岛

… : "…アッカリ~ン . .. . " .. .
June 9, 2023

Luogu P1995. [NOI2011] 智能车比赛

先复习一下 这个题。。。

#include <lastweapon/geometry>
using namespace lastweapon;
using namespace CG;

const int N = 21;

DB dp[N][4], x[N], y[N][4];
int n;

bool ok(int i0, int j0, int i1, int j1) {
    Line s(Po(x[i0], y[i0][j0]), Po(x[i1], y[i1][j1]));
    FOR(i, i0+1, i1) {
        if(Seg(Po(x[i], y[i][0]), Po(x[i], y[i][1])).sgn(s) < 0 &&
           Seg(Po(x[i], y[i][2]), Po(x[i], y[i][3])).sgn(s) < 0) return 0;
    }
    return 1;
}

int main() {

#ifndef ONLINE_JUDGE
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif

    RD(n); REP(j, 4) y[0][j] = 5;
    REP_1(i, n) {
        RF(x[i]); REP(j, 4) RF(y[i][j]);
    }
    x[++n] = 10; REP(j, 4) y[n][j] = 5;
    REP_1(i, n) REP(j, 4) dp[i][j] = OO;

    FOR(i, 0, n) REP(j, 4) FOR_1(ii, i+1, n) REP(jj, 4) {
        if (ok(i, j, ii, jj)) checkMin(dp[ii][jj], dp[i][j] + dist(Po(x[i], y[i][j]), Po(x[ii], y[ii][jj])));
    }

    printf("%.2f\n", dp[n][0]);
}

然后可以先直接输出 dist(s, t) 怒骗 20 分。。。(因为你数据里肯定也必须有这种类型的数据吧。。。)

#include <lastweapon/geometry>
using namespace lastweapon;
using namespace CG;

const int N = int(2e3) + 9;

struct Rect {
    int x0, y0, x1, y1;
    void in() {
        RD(x0, y0, x1, y1);
    }
} R[N];
DB f[N][2]; Po s, t;
int n;

DB gao() {
    return dist(s, t);
}

int main() {

#ifndef ONLINE_JUDGE
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif

    RD(n); REP(i, n) R[i].in(); s.in(); t.in();
    printf("%9f\n", gao() / RF());
}

核心的区别就是 vijos 那个题,我可以 O(n3) dp,暴力 check 两点之间的可达性。.而 NOI 这个题,每次只有一段空隙,所以可通过区域是一个不断缩小的扇形。。于是复杂度就 O(n2) 了。

顺便原版 vijos 的那个版本,其实我们也可以用平衡木来维护可通过的区域。。。
回到实现。。孤立的 s 点和 t 点很烦。。而且有很多 corner case。。

我们想办法把 s 和 t 都视为一个退化的矩形。。。。这样我就不用写额外的代码了。

#include <lastweapon/geometry>
using namespace lastweapon;
using namespace CG;

const int N = int(2e3) + 9;

struct Rect {
    int x0, y0, x1, y1;
    void in() {
        RD(x0, y0, x1, y1);
    }
} R[N];
DB f[N][2]; int l[N], r[N]; Po s, t;

int n;

bool cmp(const Rect R, int x) {
    return R.x1 < x;
}

DB gao() {

    int si = lower_bound(R+1, R+n+1, s.x, cmp) - R;
    int ti = lower_bound(R+1, R+n+1, t.x, cmp) - R;
    if (si > ti) swap(si, ti), swap(s, t);

    if (R[si].x1 != s.x) --si;
    ++ti; if (R[ti].x0 == t.x) ++ti;

    R[si].x1 = s.x; R[si].y0 = R[si].y1 = s.y;
    R[ti-1].x1 = t.x; R[ti].x0 = t.x; R[ti].y0 = R[ti].y1 = t.y;
    FOR(i, si+1, ti) f[i][0] = f[i][1] = OO; f[si][0] = f[si][1] = 0;
    FOR(i, si, ti) l[i] = max(R[i].y0, R[i+1].y0), r[i] = min(R[i].y1, R[i+1].y1);
    --ti;

#define u f[i][j]
#define v f[ii][jj]
#define w dist(pu, pv)

    FOR(i, si, ti) REP(j, 2) {
        Po pu(R[i].x1, j ? r[i] : l[i]);
        DB ar = PI/2, al = -ar;

        //cout << pu << ": " << u << endl;

        FOR_1(ii, i+1, ti) REP(jj, 2) {
            Po pv(R[ii].x1, jj ? r[ii] : l[ii]);
            DB t = atan2(pv.y-pu.y, pv.x-pu.x); if (t > PI) t -= 2*PI;
            if (al <= t && t <= ar) checkMin(v, u + w);
            if (jj) checkMin(ar, t); else checkMax(al, t);
        }
    }
    return f[ti][0];
}

int main() {

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif

    RD(n); REP_1(i, n) R[i].in(); s.in(); t.in();
    printf("%9f\n", gao() / RF());
}