1 条题解

  • 11
    @ 2024-11-17 13:57:10

    闲话

    当我往代码的某个位置加上了一个 = 号后,我的代码的内存占用缩小至了原来的 12n\frac{1}{2^n}。我并没有开玩笑。同时,运行效率也提高了不知道多少倍,因为没加等号的程序运行第 33 个样例时需要占用 10G+ 的内存,而我的电脑是撑不住的,所以我把它 Ctrl-C 了,不知道实际运行时间。而加了等号之后,所有样例运行时间都未超过 200200 毫秒。

    题解

    考虑如下算法:

    假设目前走到了位置 xx。从位置 00 到位置 xx 有若干种可能的方案,其中每种方案可以使用二元组 (t,v)(t,v) 表示。其中,tt 代表走到这个位置的总用时,而 vv 代表目前行进 11 个单位长度所用的时间。

    我们称一个二元组集合 SS精悍的,当且仅当该集合内任意两个相异二元组 (t,v)(t,v)(t,v)(t',v') 不满足 ttvvt\le t'\land v\le v'

    定义一次清理为将一个二元组集合 SS 转换为它的一个精悍的子集 SS',并且在其中 tt 的最小值尽可能小的前提下 S|S'| 尽可能大。

    定义一次距离为 xx 的步进为将一个二元组集合 SS 内的每个元素 (t,v)(t,v) 转换为 (t+xv,v)(t+xv,v)

    定义一次参数为 (t,x)(t',x') 的可能加油为设集合 SS' 为集合 SS一对一映射 (t,v)(t+t,vx)(t,v)\to (t+t',\frac{v}{x'}),令 SSSS\leftarrow S\cup S'

    可能加油询问统称为事件

    初始时,令 SS{(0,1),(109,0)}\{(0,1),(10^9,0)\}。第一个元素为初始状态,第二个元素为不加油的边界条件。

    接下来,将询问与加油站放在一起排序,令新的位置数组为 pp',大小为 (n+m)(n+m)。令 p0=0p'_0=0,则依次对于第 ii 个事件,执行一次距离为 (pipi1)(p'_i-p'_{i-1}) 的步进,并进行清理。接下来,若该事件为询问,则答案为 SS 中所有元素中最小的 tt 值。否则执行一次参数为 (ti,xi)(t_i,x_i) 的可能加油,并进行清理

    我无法分析上述做法的准确时间复杂度,但上述方法确实可以通过此题。

    代码

    #include <algorithm>
    #include <cctype>
    #include <cstdio>
    #include <list>
    using namespace std;
    const int N = 2e5 + 10, inf = 1e9;
    using ld = long double;
    const ld eps = 1e-7;
    template <typename _Tp> inline void read(_Tp &x)
    {
        char ch;
        while (ch = getchar(), !isdigit(ch))
            ;
        x = (ch ^ 48);
        while (ch = getchar(), isdigit(ch))
            x = (x << 3) + (x << 1) + (ch ^ 48);
    }
    template <typename _Tp, typename... _Args> inline void read(_Tp &x, _Args &...args)
    {
        read(x);
        read(args...);
    }
    struct st
    {
        ld ctm, spd;
        bool operator<(const st &x) const
        {
            if (ctm != x.ctm)
                return ctm > x.ctm;
            return spd < x.spd;
        }
    };
    struct evrt
    {
        int p, t, x;
        bool operator<(const evrt &tx) const
        {
            if (p != tx.p)
                return p < tx.p;
            if (t != tx.t)
                return t < tx.t;
            return x < tx.x;
        }
    } evnt[N];
    list<st> curwk, buf;
    int n, m, cur;
    ld res[N];
    void clr()
    {
        curwk.sort();
        for (auto &i : curwk)
        {
            while (buf.size() and buf.back().spd >= i.spd)
                buf.pop_back();
            buf.emplace_back(i);
        }
        curwk.swap(buf);
        buf.clear();
    }
    void frwd(int x)
    {
        cur += x;
        for (auto &i : curwk)
        {
            i.ctm += i.spd * x;
        }
        clr();
    }
    void charge(evrt a)
    {
        // if (a.x == 1)
        //     return;
        int tmp = curwk.size();
        auto it = curwk.begin();
        for (int i = 0; i < tmp; i++)
        {
            curwk.emplace_back(st{it->ctm + a.t, it->spd / a.x});
            if (curwk.back().spd * (inf - cur) < eps)
                curwk.back().spd = 0;
            it++;
        }
        clr();
    }
    int main()
    {
        freopen("ship.in", "r", stdin);
        freopen("ship.out", "w", stdout);
        read(n, m);
        curwk.emplace_back(st{0, 1});
        curwk.emplace_back(st{1e9, 0});
        for (int i = 1; i <= n; i++)
        {
            read(evnt[i].p, evnt[i].t, evnt[i].x);
        }
        for (int i = 1; i <= m; i++)
        {
            read(evnt[i + n].p);
            evnt[i + n].t = -1;
            evnt[i + n].x = i;
        }
        sort(evnt + 1, evnt + n + m + 1);
        for (int i = 1; i <= n + m; i++)
        {
            if (cur != evnt[i].p)
                frwd(evnt[i].p - cur);
            if (~evnt[i].t)
            {
                charge(evnt[i]);
                continue;
            }
            res[evnt[i].x] = curwk.back().ctm;
        }
        for (int i = 1; i <= m; i++)
        {
            printf("%.7Lf\n", res[i]);
        }
    }
    
    • @ 2024-11-19 13:39:14

      您好,

      我们称一个二元组集合 SS精悍的,当前仅当该集合内任意两个相异二元组 (t,v)(t, v)(t,v)(t', v') 不满足 ttvvt \le t' \land v \le v'

      此处是否应为 ttvvt \le t' \land v \ge v'
      UPD:不好意思我搞错了/wul 我还以为 vv 是速度

  • 1

信息

ID
94
时间
3000ms
内存
512MiB
难度
6
标签
递交数
804
已通过
174
上传者