不等式
1. 算法分析
1.1 排序不等式
排序不等式如下:
1.2 绝对值不等式
求 f ( x ) = ∣ x 1 − x ∣ + ∣ x 2 − x ∣ + . . . + ∣ x n − x ∣ f(x) = |x1 - x| + |x2 - x| + ... + |xn - x| f(x)=∣x1−x∣+∣x2−x∣+...+∣xn−x∣的最小值
结论:
将 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 4∼8,即 4 、 5 、 6 、 7 、 8 4、5、6、7、8 4、5、6、7、8。
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,那么说明给的糖果数目为正数;否则为负数。
因此预处理出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;
}