1 条题解

  • 0
    @ 2025-8-24 22:10:11

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar hehezhou
    **

    搬运于2025-08-24 22:10:11,当前版本为作者最后更新于2019-05-21 13:03:03,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    题意

    给定{an}\{a_n\},{bn}\{b_n\}
    i=1kaix+bi\sum_{i=1}^k|a_ix+b_i| 的最小值(k[1,n])(\forall k\in[1,n])

    首先根据小学数学知识,我们把它转化为:

    i=0kaix+biai\sum_{i=0}^k|a_i|*|x+\frac{b_i}{a_i}|

    考虑实际意义,一条数轴上有mm个点,要求数轴上一点,使该点到各点的距离和最小
    显然, 当这个点为第m+12\frac{m+1}2个点时为一个最优解(即中位数)

    然后用平衡树维护中位数,并统计答案即可(当然你用两个堆也可以)

    注意总个数可能爆intint

    Talk is cheap, show me the code.

    码风很丑,大佬轻喷

    #include <bits/stdc++.h>
    using namespace std;
    // 以下平衡树(无旋treap)
    struct node {
        int rnd, cnt, ls, rs;
        long long size;
        double sum, key;
    } t[500010];
    inline int newnode(double key, int cnt) {
        static int Cnt = 0;
        t[++Cnt] = node{rand(), cnt, 0, 0, (long long)cnt, key * cnt, key};
        return Cnt;
    }
    inline void up(int x) {
        t[x].size = t[t[x].ls].size + t[t[x].rs].size + t[x].cnt;
        t[x].sum = t[t[x].ls].sum + t[t[x].rs].sum + t[x].key * t[x].cnt;
    }
    inline int merge(int a, int b) {
        if(a == 0 || b == 0) return a | b;
        if(t[a].rnd < t[b].rnd) return t[a].rs = merge(t[a].rs, b), up(a), a;
        return t[b].ls = merge(a, t[b].ls), up(b), b;
    }
    inline void split_key(int now, double k, int &x, int &y) {
        if(now == 0) x = y = 0;
        else if(t[now].key > k) y = now, split_key(t[now].ls, k, x, t[y].ls), up(y);
        else x = now, split_key(t[now].rs, k, t[x].rs, y), up(x);
    }
    inline void split_rank(int now, long long k, int &x, int &y) {
        if(now == 0) x = y = 0;
        else if(t[t[now].ls].size >= k) y = now, split_rank(t[now].ls, k, x, t[y].ls), up(y);
        else x = now, split_rank(t[now].rs, k - t[t[now].ls].size - t[now].cnt, t[x].rs, y), up(x);
    }
    inline double get_max(int now) {
        if(t[now].rs) return get_max(t[now].rs);
        return t[now].key;
    }
    //平衡树结束
    int n, a[500010], b[500010], rt;
    double lala;
    int main() {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%d", a + i);
        for(int i = 1; i <= n; i++) scanf("%d", b + i);
        for(int i = 1; i <= n; i++) {
            if(a[i] < 0) a[i] = -a[i], b[i] = -b[i]; //加绝对值
            int x, y;
            if(a[i] == 0) lala += abs(b[i]); //特判
            else {
                double add = -1.0 * b[i] / a[i];
                split_key(rt, add, x, y);
                rt = merge(merge(x, newnode(add, a[i])), y);
            }
            double mid;
            split_rank(rt, (t[rt].size + 1) / 2, x, y);
            mid = get_max(x);
            printf("%.10lf\n", lala + mid * t[x].size - t[x].sum + t[y].sum - mid * t[y].size);
            rt = merge(x, y);
        }
        return 0;//完结撒花
    }
    
    • 1

    信息

    ID
    4367
    时间
    3000ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者