中位数及带权中位数题集

Posted wangwangyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了中位数及带权中位数题集相关的知识,希望对你有一定的参考价值。

codevs 3625

技术分享图片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int x[11111], y[11111];
 4 int main()
 5 {
 6     int n; scanf("%d", &n);
 7     for(int i = 1; i <= n; i++) scanf("%d %d", &x[i], &y[i]);
 8     ///先处理y
 9     sort(y + 1, y + n + 1);
10     long long ans = 0;
11     int mid = n / 2 + 1;
12     for(int i = 1; i <= n; i++) ans += abs(y[mid] - y[i]);
13     ///再处理x
14     sort(x + 1, x + n + 1);
15     for(int i = 1; i <= n; i++) x[i] -= (i - 1);
16     sort(x + 1, x + n + 1);
17     for(int i = 1; i <= n; i++) ans += abs(x[mid] - x[i]);
18     printf("%lld
", ans);
19     return 0;
20 }
Code

Codeforces Round #512 (Div. 2, based on Technocup 2019 Elimination Round 1) F. Putting Boxes Together

题解真的又写的非常清楚了……

自己在想的时候,确实想到肯定有一个块不动,其他的动,我们只需要去移那些贡献小的,我猜是最重的那个,但自己写了组样例就推翻了。

题解讲,用$S(l,r)$表示将索引$(l,r)$物品移动一步的花费,不动的那块应该满足$S(l,k-1)≤ frac{S(l,r)}{2}$,$S(l,k)> frac{S(l,r)}{2}$。Q神说是熟知的带权中位数问题

 求$k$的过程,可以用二分+树状数组解决。

求得$k$后,因为$k$是固定不动的,如果$i<k$,那么花费是$sum_{i in[l, k-1]} {w_{i}(a_{k}-a_{i}-(k-i))}$,令$a_{i}=a_{i}-i$,那么原式$= sum_{i in[l, k-1]} {w_{i}(a_{k}-a_{i})}=a_{k} imes S(l,k-1)-sum_{i in[l, k-1]} {w_{i}a_{i}}$,再用一颗树状数组来维护$w_{i} a_{i}$就可以了。$i > k$类似。

真的是慎用除法,不然都不知道怎么死的……

技术分享图片
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int maxn = 2e5 + 50;
ll a[maxn], w[maxn];
ll C[maxn];
int n, q;
void add1(int x, ll v)
{
    while(x <= n)
    {
        C[x] += v;
        x += x & -x;
    }
}
ll query1(int x)
{
    ll res = 0;
    while(x > 0)
    {
        res += C[x];
        x -= x & -x;
    }
    return res;
}
ll calc(int l, int r)
{
    if(r < l) return 0;
    ll ans = query1(r) - query1(l - 1);
   // printf("%lld
", ans);
    return ans;
}
ll D[maxn];
void add2(int x, ll v)
{
    while(x <= n)
    {
        D[x] += v;
        D[x] %= mod;
        x += x & -x;
    }
}
ll query2(int x)
{
    ll res = 0;
    while(x > 0)
    {
        res += D[x];
        res %= mod;
        x -= x & -x;
    }
    return res;
}
ll calc2(int l, int r)
{
    if(r < l) return 0;
    return (query2(r) - query2(l - 1) + mod) % mod;
}
int main()
{
    scanf("%d %d", &n, &q);
    for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    for(int i = 1; i <= n; i++) scanf("%lld", &w[i]), add1(i, w[i]), a[i] = a[i] - i, add2(i, w[i] * a[i] % mod);
    while(q--)
    {
        int l, r; scanf("%d %d", &l, &r);
        ///首先二分
        if(l > 0)
        {
            ll S = calc(l, r);
            int k = 0;
            int tmpl = l, tmpr = r;
            while(tmpl <= tmpr)
            {
                int mid = (tmpl + tmpr) >> 1;
                if(calc(l, mid - 1) * 2LL < S && calc(l, mid) * 2LL < S)
                {
                    tmpl = mid + 1;
                }
                else if(calc(l, mid - 1) * 2LL > S && calc(l, mid) * 2LL > S)
                {
                    tmpr = mid - 1;
                }
                else
                {
                    k = mid;
                    break;
                }
            }
            ///得到k后,开始计算花费
            ll ans = (calc(l, k - 1) % mod * a[k] % mod - calc2(l, k - 1) + mod) % mod;
            ans = (ans + (calc2(k + 1, r) - calc(k + 1, r) % mod * a[k] % mod + mod) % mod) % mod;
            printf("%lld
", ans);
        }
        else
        {
            int id = -l;
            ll nw = r;
            add1(id, nw - w[id]), add2(id, (a[id] * nw % mod - a[id] * w[id] % mod + mod) % mod);
            w[id] = nw;
        }
    }
    int ccc = 0;
    return 0;
}
Code

 

sgu 114

POJ 1723 SOLDIERS

POJ 1160

ZOJ 1196

以上是关于中位数及带权中位数题集的主要内容,如果未能解决你的问题,请参考以下文章

[总结]中位数及带权中位数问题

poj 1723 SOLDIERS 带权中位数

带权中位数

Putting Boxes Together CodeForces - 1030F (带权中位数)

OJ题集m的n次方的最后三位数

51Nod 1110 距离之和最小 V3 中位数 思维