不等式小结

不等式

1. 算法分析

1.1 排序不等式

排序不等式如下:
Image.png

1.2 绝对值不等式

f ( x ) = ∣ x 1 − x ∣ + ∣ x 2 − x ∣ + . . . + ∣ x n − x ∣ f(x) = |x1 - x| + |x2 - x| + ... + |xn - x| f(x)=x1x+x2x+...+xnx的最小值

结论:

x 1 , x 2... , x n x1,x2...,xn x1,x2...,xn排序。

n n n为奇数时, x = x ( n / 2 ) x=x(n/2) x=x(n/2);当 n n n为偶数时,x取 x ( n / 2 )   x ( n / 2 + 1 ) x(n/2) ~ x(n/2+1) x(n/2) x(n/2+1),都能够使得 f ( x ) f(x) f(x)取值最小。

例如: x = [ 1 , 3 , 5 ] x = [1, 3, 5] x=[1,3,5],则要使得 f ( x ) f(x) f(x)最小,那么 x x x只能为 3 3 3;而如果 x = [ 2 , 4 , 8 , 10 ] x=[2, 4, 8, 10] x=[2,4,8,10],要是的 f ( x ) f(x) f(x)最小,那么 x x x取值为 4 ∼ 8 4 \sim 8 48,即 4 、 5 、 6 、 7 、 8 4、5、6、7、8 45678

2. 典型例题

2.1 排序不等式

acwing913. 排队打水
题意: 有 n 个人排队到 1 个水龙头处打水,第 i 个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?1≤n≤105,1≤ti≤104
题解: 第n个人的等待时间为s[n] = (n - 1)*a[1] + (n - 1 - 1) * a[2] + (n - 1 - 2) * a[3]; 可以使用反证法证明把人的等待时间从小到大排序的正确性,本题推出公式之后发现是排序不等式,顺序和>=乱序和>=逆序和,所以要求最小,完全可以选择逆序和,则a[1] <= a[2] <=… <= a[n]
代码:

#include <bits/stdc++.h>

using namespace std;

int const N = 1e5 + 10;
int a[N];
int n;

int main() {
    cin >> n;
    for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    sort(a, a + n);  // 按照排序不等式要从小到大
    long long res = 0;
    for (int i = 0; i < n; ++i) res += a[i] * (n - 1 - i);  // 排序不等式累加
    cout << res << endl;
    return 0;
}

2.2 绝对值不等式

acwing104 货仓选址
题意: 在一条数轴上有 N 家商店,它们的坐标分别为 A1~AN。现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。 1≤N≤100000
题解: 绝对值不等式板题
代码:

#include <bits/stdc++.h>

using namespace std;

int const N = 1e5 + 10;
int a[N];
int n;

int main() {
    cin >> n;
    for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    sort(a, a + n);  // 排序
    int res = 0;
    for (int i = 0; i < n; ++i) res += abs(a[i] - a[n / 2]);  // 绝对值不等式累加
    cout << res << endl;
    return 0;
}

acwing122. 糖果传递
题意: 有n个小朋友坐成一圈,每人有a[i]个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。求使所有人获得均等糖果的最小代价。
题解: 设第i个人需要给左边的人xi个糖果,因此就会有如下的推导,如果xi>0,那么说明给的糖果数目为正数;否则为负数。
Screenshot_20200930_194817.jpg
Screenshot_20200930_194833.jpg
因此预处理出c数组,然后使用中位数处理即可。
代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
int const N = 1000010 ;
LL c[N], a[N], n, sum;

int main() {
    cin >> n ;
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", a + i);
        sum += a[i];
    }
    LL avg = sum / n;
    
    for (int i = 1; i <= n; ++i) {
        c[i] = c[i - 1] + avg - a[i];
    }
    sort(c + 1, c + 1 + n);
    LL res = 0;
    for (int i = 1; i <= n; ++i) res += llabs(c[i] - c[(n + 1) / 2]);
    cout << res << endl;
    return 0;
}

CF486B. Eastern Exhibition

题意: 给定平面上n个点,要求在平面上找到点x,使得x点到n个点的距离和最小。问这样的x有多少个? 1 < = n < = 1000 1<=n<=1000 1<=n<=1000

题解: 中位数结论。把x轴和y轴分开看。对于n个点,如果n为奇数,那么这样的点只有一个,就是中位数;如果n为偶数,那么这样的点有中间两个数相减个,即 a [ n / 2 + 1 ] − a [ n ] a[n/2+1]-a[n] a[n/2+1]a[n]个。

代码:

#include <bits/stdc++.h>

#define int long long
using namespace std;

int const MAXN = 1e3 + 10;
int n, m, T;
int x[MAXN], y[MAXN];

signed main() {
    cin >> T;
    while(T--) {
        cin >> n;
        int res = 0;
        for (int i = 0; i < n; ++i) cin >> x[i] >> y[i];
        sort(x, x + n), sort(y, y + n);
        if (n & 1) res = 1;
        else res = (x[n / 2] - x[n / 2 - 1] + 1) * (y[n / 2] - y[n / 2 - 1] + 1);
        cout << res << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值