1 条题解

  • 0
    @ 2025-8-24 23:07:05

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar lalaouye
    星河滚烫,你是人间理想。

    搬运于2025-08-24 23:07:05,当前版本为作者最后更新于2025-04-09 17:27:45,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    考虑一条线怎么做?

    首先排除解方程,这样精度爆炸。有两种方法,一种是很自然的把它放到平面直角坐标系中,我们考虑找到它与 xx 轴的一个交点,可以利用三分找出,然后再三分找一个交点就可以解出来了。

    现在有很多条线,不难发现我们固定一条线,设 f(t)f(t)(x0,t)(x_0,t) 查询的答案,它为一堆绝对值函数相加,它是一个凸包。我们希望找出交点,但是交点错综复杂,然而题目保证斜率互不相同且值域很小,我们找一个巨大的 x0x_0 再找出所有关系就能明确对应关系了。

    怎么找呢?考虑分治。考虑对于分治区间 [x,y][x,y],如果 f(x)+f(y)2=f(x+y2)\frac{f(x)+f(y)}{2}=f(\frac{x+y}{2}) 则说明该区间只有一条线,没有交点,直接不管。否则进入 [x,x+y2][x,\frac{x+y}{2}][x+y2,y][\frac{x+y}{2},y] 即可。这样是 O(nlogV)\mathcal{O}(n\log V) 的,据说精细实现能过。

    考虑优化,发现点数和线段数很少,那么我们考虑找出最左边和最右边的两个线段,分治时求出他们的交点 midmid,如果交点在图上,这意味着我们找出了一个点,利用它算出直线并结束分治。否则我们能够找出一条线的信息,那么我们只需优化 3n+23n+2 次操作就能完成。

    代码:

    #include <bits/stdc++.h>
    #define rep(i, l, r) for (int i (l); i <= (r); ++ i)
    #define rrp(i, l, r) for (int i (r); i >= (l); -- i)
    #define eb emplace_back
    using namespace std;
    #define pii pair <ll, ll>
    #define inf 1000000000
    #define ls (p << 1)
    #define rs (ls | 1)
    #define id(x, y) ((x - 1) * m + y)
    constexpr int N = 1e5, len = 2e4, P = 998244353;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    long double query(long double x, long double y);
    void the_lines_are(std::vector<int> a, std::vector<int> b);
    class node {
      public:
      ld k, b;
    } ;
    vector <int> A, B;
    node get (ld x) {
      int p = floor (x / N);
      ld d1 (query (N, p * N + len)), d2 (query (N, (p + 1) * N - len));
      ld k ((d1 - d2) / (len * 2 - N));
      return (node) {k, d1 - k * (p * N + len)};
    }
    void find (node x, node y) {
      if (fabsl (x.k - y.k) < 1e-5) return ;
      ld mid = - (x.b - y.b) / (x.k - y.k);
      ld val = query (N, mid);
      if (fabsl (x.k * mid + x.b - val) < 1e-5 && fabsl (y.k * mid + y.b - val) < 1e-5) {
        ld k = mid / N;
        A.eb (round (k));
        B.eb (round (mid - 1.0 * round (k) * N));
        return ;
      } node Mid = get (mid);
      find (x, Mid), find (y, Mid);
    }
    void solve (int N, int subtask) {
      find (get (-2e9), get (2e9));
      the_lines_are (A, B);
    }
    
    • 1

    信息

    ID
    11144
    时间
    3000ms
    内存
    250MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者