排队不等式
原题链接
https://www.acwing.com/problem/content/915/
题目大意:
有 n 个人排队到 1 个水龙头处打水,第 i 个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?
思路:
从小到大排序,时间短的人先打水。
证明:
假设总时间为
r
e
s
=
t
1
(
n
−
1
)
+
t
2
(
n
−
2
)
+
.
.
.
+
t
n
(
n
−
n
)
res = t_1(n-1)+t_2(n-2)+...+t_n(n-n)
res=t1(n−1)+t2(n−2)+...+tn(n−n),如果res是最优解,一定有
t
i
<
=
t
i
+
1
t_i<=t_{i+1}
ti<=ti+1。
反证法:
如果
t
i
>
t
i
+
1
t_i>t_{i+1}
ti>ti+1,交换
t
i
t_i
ti和
t
i
+
1
t_{i+1}
ti+1的打水顺序。
交换前:
r
e
s
1
=
.
.
.
+
t
i
(
n
−
i
)
+
t
i
+
1
(
n
−
i
−
1
)
+
.
.
.
res_1 = ...+t_i(n-i)+t_{i+1}(n-i-1)+...
res1=...+ti(n−i)+ti+1(n−i−1)+...
交换后:
r
e
s
2
=
.
.
.
+
t
i
+
1
(
n
−
i
)
+
t
i
(
n
−
i
−
1
)
+
.
.
.
res_2 = ...+t_{i+1}(n-i)+t_i(n-i-1)+...
res2=...+ti+1(n−i)+ti(n−i−1)+...
另
a
n
s
=
r
e
s
1
−
r
e
s
2
=
t
i
−
t
i
+
1
>
0
ans = res1-res2=t_i-t_{i+1}>0
ans=res1−res2=ti−ti+1>0,所以交换后总时间会变少,说明
r
e
s
1
res_1
res1不是最优解。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5+5;
int a[N];
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
LL res=0;
for(int i=0;i<n;i++){
res+=a[i]*(n-1-i);
}
cout<<res<<endl;
return 0;
}
绝对值不等式
原题链接
https://www.acwing.com/problem/content/106/
题目大意:
在一条数轴上有 N 家商店,它们的坐标分别为
A
1
∼
A
N
A_1∼A_N
A1∼AN。
现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。
为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。
思路:
找n个点的中位数,这个数就是距离的最小值点。
证明:
设
r
e
s
=
∣
x
1
−
x
0
∣
+
∣
x
2
−
x
0
∣
+
.
.
.
+
∣
x
1
−
x
n
∣
,
x
i
res=|x_1-x_0|+|x_2-x_0|+...+|x_1-x_n|,x_i
res=∣x1−x0∣+∣x2−x0∣+...+∣x1−xn∣,xi表示商店位置
(
x
i
<
x
i
+
1
)
(x_i<x_{i+1})
(xi<xi+1),
x
0
x_0
x0表示货仓的位置。
若商店数量为偶数家:
r
e
s
=
(
∣
x
1
−
x
0
∣
+
∣
x
n
−
x
0
∣
)
+
.
.
.
+
(
∣
x
n
2
−
x
n
∣
+
∣
x
n
+
1
2
∣
)
res=(|x_1-x_0|+|x_n-x_0|)+...+(|x_{\frac n 2}-x_n|+|x_{\frac {n+1}2}|)
res=(∣x1−x0∣+∣xn−x0∣)+...+(∣x2n−xn∣+∣x2n+1∣)
若商店数量为奇数家:
r
e
s
=
(
∣
x
1
−
x
0
∣
+
∣
x
n
−
x
0
∣
)
+
.
.
.
+
∣
x
n
2
−
x
0
∣
res=(|x_1-x_0|+|x_n-x_0|)+...+|x_{\frac n 2}-x_0|
res=(∣x1−x0∣+∣xn−x0∣)+...+∣x2n−x0∣
若要res最小,只需要让括号内的每个数都最小,而
∣
x
i
−
x
0
∣
+
∣
x
j
−
x
0
∣
|x_i-x_0|+|x_j-x_0|
∣xi−x0∣+∣xj−x0∣在
x
0
x_0
x0取值在
[
x
i
,
x
j
]
[x_i,x_j]
[xi,xj]这个区间时,取到最小值。而由于
(
x
i
<
x
i
+
1
)
(x_i<x_{i+1})
(xi<xi+1),所以
[
x
i
,
x
n
−
i
]
[x_i,x_{n-i}]
[xi,xn−i]这个区间一定包括在
[
x
i
−
1
,
x
n
−
i
+
1
]
[x_{i-1},x_{n-i+1}]
[xi−1,xn−i+1]这个区间当中。
所以最终如果n是偶数,则
x
0
x_0
x0是
[
x
n
2
,
x
n
+
1
2
]
[x_{\frac n 2},x_{\frac {n+1}2}]
[x2n,x2n+1]这个区间当中的任意一个点。
如果n是奇数,则
x
0
x_0
x0是
x
n
2
x_{\frac n 2}
x2n这个点。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5+5;
int a[N];
int n;
int main(){
cin>>n;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
LL res=0;
for(int i=0;i<n;i++) res+=abs(a[i]-a[n/2]);
cout<<res<<endl;
return 0;
}
推公式
原题链接
https://www.acwing.com/problem/content/127/
题目大意
农民约翰的 N 头奶牛(编号为 1…N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。奶牛们不是非常有创意,只提出了一个杂技表演:叠罗汉
表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。这 N头奶牛中的每一头都有着自己的重量 Wi 以及自己的强壮程度 Si。
一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。
您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能小。
思路:
根据w[i]+s[i]的值从小到大排序,总和最小的牛叠在最上面。算最大的风险数。
证明:
设x为我们算出的解,ans为最优解。
1.证明x>=ans
因为x是可行解,所以x一定>=ans
2.证明x<=ans
设存在i使得,
s
[
i
]
+
w
[
i
]
>
s
[
i
+
1
]
+
w
[
i
+
1
]
s[i]+w[i]>s[i+1]+w[i+1]
s[i]+w[i]>s[i+1]+w[i+1]
已知:
i和i+1位置的牛在交换前:
第i号位置的牛的风险指数是:
w
[
0
]
+
w
[
1
]
+
.
.
.
+
w
[
i
−
1
]
−
s
[
i
]
w[0]+w[1]+...+w[i-1]-s[i]
w[0]+w[1]+...+w[i−1]−s[i]
第i+1号位置的牛的风险指数是:
w
[
0
]
+
w
[
1
]
+
.
.
.
+
w
[
i
]
−
s
[
i
+
1
]
w[0]+w[1]+...+w[i]-s[i+1]
w[0]+w[1]+...+w[i]−s[i+1]
i和i+1位置的牛在交换后:
第i号位置的牛的风险指数是:
w
[
0
]
+
w
[
1
]
+
.
.
.
+
w
[
i
−
1
]
−
s
[
i
+
1
]
w[0]+w[1]+...+w[i-1]-s[i+1]
w[0]+w[1]+...+w[i−1]−s[i+1]
第i+1号位置的牛的风险指数是:
w
[
0
]
+
w
[
1
]
+
.
.
.
+
w
[
i
−
1
]
+
w
[
i
+
1
]
−
s
[
i
]
w[0]+w[1]+...+w[i-1]+w[i+1]-s[i]
w[0]+w[1]+...+w[i−1]+w[i+1]−s[i]
因为我们比较的是风险指数的最大值,所以可以对上式同时进行变换。同时减去
(
w
[
0
]
+
w
[
1
]
+
.
.
.
+
w
[
i
−
1
]
−
s
[
i
]
−
s
[
i
+
1
]
)
(w[0]+w[1]+...+w[i-1]-s[i]-s[i+1])
(w[0]+w[1]+...+w[i−1]−s[i]−s[i+1])
i和i+1位置的牛在交换前:
第i号位置的牛的风险指数是:
s
[
i
+
1
]
s[i+1]
s[i+1]
第i+1号位置的牛的风险指数是:
w
[
i
]
+
s
[
i
]
w[i]+s[i]
w[i]+s[i]
i和i+1位置的牛在交换后:
第i号位置的牛的风险指数是:
s
[
i
]
s[i]
s[i]
第i+1号位置的牛的风险指数是:
w
[
i
+
1
]
+
s
[
i
+
1
]
w[i+1]+s[i+1]
w[i+1]+s[i+1]
因为
w
[
i
]
+
s
[
i
]
>
w
[
i
+
1
]
+
s
[
i
+
1
]
w[i]+s[i]>w[i+1]+s[i+1]
w[i]+s[i]>w[i+1]+s[i+1]并且
w
[
i
]
+
s
[
i
]
>
s
[
i
]
w[i]+s[i]>s[i]
w[i]+s[i]>s[i],所以在交换位置后,风险最大值一定变小了。所以x一定比所有的解都要小。
因为
a
n
s
<
=
x
<
=
a
n
s
ans<=x<=ans
ans<=x<=ans,所以
x
=
=
a
n
s
x==ans
x==ans
证毕。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 50005;
int n;
PII cow[N];
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
int w, s;
scanf("%d%d", &w, &s);
cow[i] = { w + s,w };
}
sort(cow, cow + n);
int res = -2e9, sum = 0;
for (int i = 0; i < n; i++) {
int w = cow[i].second, s = cow[i].first - w;
res = max(res, sum - s);
sum+=w;
}
cout << res << endl;
return 0;
}